2012-07-26 17 views
8

Quiero manejar un caso donde hay una clave principal o conflicto de clave único, también conocido como una entrada duplicada. Para esto estoy atrapando el IntegrityError, que capta el error muy bien. El problema es que parece que no puedo encontrar ningún mensaje de error simple o código de error para verificar. Todo lo que estoy recibiendo es la propiedad IntegrityError.message que es una cadena que tiene este aspecto:Manejo de errores SQLAlchemy: ¿cómo se hace?

(IntegrityError) (1062, "Duplicar entrada 'foobar' por 'nombre' clave")

Eso es no muy útil Usando eso voy a tener que comenzar a analizar los mensajes de error para su código y mensaje. Llamando dir en la excepción sólo muestra las siguientes propiedades:

'args', 'connection_invalidated', 'ejemplo', 'mensaje', 'orig', 'params', 'sentencia'

args es simplemente una tupla de un solo elemento con la cadena antes mencionada dentro de ella y params son los datos que traté de insertar. Parece que no puedo encontrar ninguna forma de determinar que este es realmente un error de clave duplicado sin tener que comenzar a analizar el mensaje de error usando expresiones regulares o algo así.

¿Alguien puede arrojar algo de luz sobre este tema?

Gracias

Respuesta

12

Me di cuenta de esto al escribir la pregunta por la lectura de la documentación con más cuidado. Todavía voy a publicar esto, ya que podría ser de ayuda para alguien.

En la documentación de la SQLAlchemy DBAPIError, de la que es una subclase de la IntegrityError, se explica que la excepción es simplemente un contenedor para el API error de base de datos subyacente y que el error original se guarda como orig en la excepción. Efectivamente, llamando e.orig.args consigo una tupla muy bien organizada:

(1062, "Duplicar entrada 'foobar' por 'nombre' clave")

+0

Sí, esto es muy útil. Gracias por ahorrarme tiempo para desenterrarlo. –

0

Por lo que yo sé, la única manera es para analizar la cadena de error en la excepción. No puedo encontrar ninguna tupla que especifique el error, la columna con la restricción de singularidad violada y el valor por separado.

Específicamente, uno puede buscar el mensaje de excepción utilizando un operador de búsqueda de subcadenas o una expresión regular. Por ejemplo:

db.session.add(SupplierUser(supplier_id=supplier_id, username=username, password=password, creator=user)) 
    try: 
     db.session.commit() 
    except IntegrityError as err: 
     db.session.rollback() 
     if "UNIQUE constraint failed: user.username" in str(err): 
      return False, "error, username already exists (%s)" % username 
     elif "FOREIGN KEY constraint failed" in str(err): 
      return False, "supplier does not exist" 
     else: 
      return False, "unknown error adding user" 

Sin embargo, estas cadenas pueden ser bastante largo, porque se incluye la instrucción SQL, por ejemplo:

(sqlite3.IntegrityError) UNIQUE constraint failed: user.username [SQL: 'INSERT INTO user (username, password_hash, created_time, creator_id, role, is_active, supplier_id) VALUES (?, ?, ?, ?, ?, ?, ?)'] [parameters: ('bob', ... 

Por lo tanto, no sólo puede disminuir el error de manipulación latencias de análisis sintáctico excepciones si se busca a través el mensaje de error de la base de datos, sin la información adicional de sqlalchemy. Esto se puede hacer examinando err.args, que debe ser más pequeño:

'(sqlite3.IntegrityError) UNIQUE constraint failed: supplier_user.username',) 

El ejemplo actualización:

db.session.add(SupplierUser(supplier_id=supplier_id, username=username, password=password, creator=user)) 
    try: 
     db.session.commit() 
    except IntegrityError as err: 
     db.session.rollback() 
     err_msg = err.args[0] 
     if "UNIQUE constraint failed: supplier_user.username" in err_msg: 
      return False, "error, supplier username already exists (%s)" % username 
     elif "FOREIGN KEY constraint failed" in err_msg: 
      return False, "supplier does not exist" 
     else: 
      return False, "unknown error adding user" 

nota del error de sintaxis que se utiliza aquí es para sqlite3. El análisis de un mensaje de error de excepción de mysql como:

(1062, "Duplicate entry 'usr544' for key 'username'") 

Se puede hacer con una expresión regular apropiada. Tenga en cuenta que se parece a una tupla, pero en realidad es una cadena (sqlalchemy versión 1.1.3 y mysql 5.5).

Por ejemplo:

except IntegrityError as err: 
     db.session.rollback() 
     if re.match("(.*)Duplicate entry(.*)for key 'username'(.*)", err.args[0]): 
    .... etc ....