2012-07-26 19 views
8

Voglio gestire un caso in cui è presente una chiave primaria o un conflitto di chiave univoco, ovvero una voce duplicata. Per questo sto prendendo il IntegrityError, che cattura l'errore bene. Il problema è che non riesco a trovare alcun messaggio di errore o codice di errore da verificare. Tutto quello che sto ricevendo è la proprietà IntegrityError.message che è una stringa che assomiglia a questo:Gestione errori SQLAlchemy: come è fatto?

(IntegrityError) (1062, "Duplica entry 'foobar' per la chiave 'nome'")

Ecco non molto utile. Usando che ho intenzione di iniziare a analizzare i messaggi di errore per il loro codice e il messaggio. Chiamando dir sull'eccezione mostra solo le seguenti proprietà:

'args',,, 'messaggio' 'connection_invalidated' 'esempio', 'orig', 'params', 'dichiarazione'

args è semplicemente una tupla a singolo elemento con la stringa sopra menzionata al suo interno e params sono i dati che ho provato ad inserire. Non riesco a trovare alcun modo per determinare che questo è in realtà un errore chiave duplicato senza dover effettivamente iniziare l'analisi del messaggio di errore usando espressioni regolari o qualcosa del genere.

Qualcuno può far luce su questo problema?

Grazie

risposta

12

ho capito questo durante la scrittura la questione leggendo la documentazione più attenzione. Lo pubblicherò comunque, poiché potrebbe essere d'aiuto a qualcuno.

Nella documentazione del SQLAlchemy DBAPIError, da cui il IntegrityError viene sottoclasse, si spiega che l'eccezione è solo un involucro per l'errore di database API sottostante e che l'errore originale viene salvato come orig nella eccezione. Abbastanza sicuro, chiamando e.orig.args ricevo una tupla ben organizzata:

(1062, "Duplica entry 'foobar' per la chiave 'nome'")

+0

Sì, che è molto utile. Grazie per avermi risparmiato il tempo per estrarlo. –

0

Per quanto ne so, l'unico modo è per analizzare la stringa di errore nell'eccezione. Non riesco a trovare alcuna tupla che specifica l'errore, la colonna con il vincolo di univocità violata e il valore separatamente.

In particolare, è possibile cercare il messaggio di eccezione utilizzando un operatore di ricerca sottostringa o un'espressione regolare. Per esempio:

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" 

Tuttavia, queste stringhe può essere abbastanza lungo perché l'istruzione SQL è incluso, per esempio:

(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', ... 

Così, si ridurrà al minimo l'errore di gestione latenze parsing delle eccezioni se si cerca attraverso il messaggio di errore del database, senza le informazioni aggiunte da sqlalchemy. Questo può essere fatto esaminando err.args, che dovrebbero essere più piccolo:

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

L'esempio aggiornamento:

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 la sintassi errore che ho usato qui è per sqlite3. Parsing un messaggio di errore di eccezione mysql come:

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

Può essere eseguito con un'espressione regolare appropriata. Si noti che sembra una tupla, ma in realtà è una stringa (sqlalchemy versione 1.1.3 e mysql 5.5).

Ad esempio:

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