2012-01-24 14 views
16

Utilizzando l'ORM SQLAlchemy, voglio assicurarmi che i valori siano il tipo giusto per le loro colonne.Come posso verificare i tipi di dati Colonna nell'ORM SQLAlchemy?

Ad esempio, supponiamo di avere una colonna Integer. Cerco di inserire il valore "ciao", che non è un numero intero valido. SQLAlchemy mi consentirà di farlo. Solo più tardi, quando eseguo session.commit(), viene sollevata un'eccezione: sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"….

Sto aggiungendo batch di record e non desidero eseguire il commit dopo ogni singolo add(…), per motivi di prestazioni.

Così come posso:

  • Sollevare l'eccezione, non appena faccio session.add(…)
  • Oppure, assicurarsi che il valore mi inserisco può essere convertito al tipo di dati di destinazione Colonna, prima aggiungerlo al lotto?
  • O qualsiasi altro modo per evitare che una registrazione errata possa rovinare un'intera commit().
+0

Eventuali duplicati: http://stackoverflow.com/questions/2390753/is-there-a-way-to-transparently-perform-validation -on-sqlalchemy-objects – greut

+2

@greut Non avevo ancora visto questa domanda in precedenza, ma la risposta con il punteggio più alto utilizza un valore deprecato d tecnica. L'altra risposta data è filosofica. Qui abbiamo l'autore di SQLAlchemy con una risposta precisa e utile. – Nate

risposta

27

SQLAlchemy non crea questo in quanto rimanda al DBAPI/database come la migliore e più efficiente fonte di convalida e coercizione dei valori.

Per creare la propria convalida, viene utilizzata la convalida di tipo TypeDecorator o ORM. TypeDecorator ha il vantaggio che opera nel core e può essere piuttosto trasparente, anche se si verifica solo quando SQL viene effettivamente emesso.

Per eseguire la convalida e la coercizione prima, questo è al livello ORM.

validazione può essere ad hoc, in corrispondenza dello strato ORM, via @validates:

http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators

Il sistema di eventi che @validates usi è disponibile anche direttamente. È possibile scrivere una soluzione generalizzata che collega validatori di tua scelta per i tipi di essere mappati:

from sqlalchemy import Column, Integer, String, DateTime 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import event 
import datetime 

Base= declarative_base() 

def validate_int(value): 
    if isinstance(value, basestring): 
     value = int(value) 
    else: 
     assert isinstance(value, int) 
    return value 

def validate_string(value): 
    assert isinstance(value, basestring) 
    return value 

def validate_datetime(value): 
    assert isinstance(value, datetime.datetime) 
    return value 

validators = { 
    Integer:validate_int, 
    String:validate_string, 
    DateTime:validate_datetime, 
} 

# this event is called whenever an attribute 
# on a class is instrumented 
@event.listens_for(Base, 'attribute_instrument') 
def configure_listener(class_, key, inst): 
    if not hasattr(inst.property, 'columns'): 
     return 
    # this event is called whenever a "set" 
    # occurs on that instrumented attribute 
    @event.listens_for(inst, "set", retval=True) 
    def set_(instance, value, oldvalue, initiator): 
     validator = validators.get(inst.property.columns[0].type.__class__) 
     if validator: 
      return validator(value) 
     else: 
      return value 


class MyObject(Base): 
    __tablename__ = 'mytable' 

    id = Column(Integer, primary_key=True) 
    svalue = Column(String) 
    ivalue = Column(Integer) 
    dvalue = Column(DateTime) 


m = MyObject() 
m.svalue = "ASdf" 

m.ivalue = "45" 

m.dvalue = "not a date" 

convalida e la coercizione può anche essere costruito a livello di tipo utilizzando TypeDecorator, anche se questo è solo quando viene emesso SQL, come ad come questo esempio che converte stringhe UTF-8 a Unicode:

http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode

+0

Grazie zzzeek. Non avevo mai usato il sistema degli eventi prima. Un grande esempio che mostra dove e come agganciarlo. – Nate

Problemi correlati