2012-01-24 14 views
16

Usando SQLAlchemy ORM, quiero asegurarme de que los valores sean del tipo correcto para sus columnas.¿Cómo puedo verificar los tipos de datos de columna en el SQLAlchemy ORM?

Por ejemplo, supongo que tengo una columna Entero. Intento insertar el valor "hola", que no es un número entero válido. SQLAlchemy me permitirá hacer esto. Solo más tarde, cuando ejecuto session.commit(), aparece una excepción: sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"….

Estoy agregando lotes de registros, y no quiero comprometerme después de cada add(…), por razones de rendimiento.

Entonces, ¿cómo puedo:

  • Elevar la excepción tan pronto como yo session.add(…)
  • O, asegúrese de que el valor Estoy insertando se puede convertir en el tipo de datos de columna de destino, antes agregarlo al lote?
  • O cualquier otra forma de evitar que un registro malo estropee un entero commit().
+0

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

+2

@greut No había visto esa pregunta antes, pero la respuesta mejor calificada usa una obsoleta d técnica. La otra respuesta dada es filosófica. Aquí tenemos al autor de SQLAlchemy con una respuesta precisa y útil. – Nate

Respuesta

27

SQLAlchemy no incorpora esto ya que difiere de la base de datos/DBAPI como la mejor y más eficiente fuente de validación y coerción de valores.

Para construir su propia validación, generalmente se utiliza la validación de TypeDecorator o ORM-level. TypeDecorator tiene la ventaja de que funciona en el núcleo y puede ser bastante transparente, aunque solo ocurre cuando realmente se emite SQL.

Para hacer la validación y la coerción antes, esto es en el nivel ORM.

validación se puede ad-hoc, en la capa ORM, a través de @validates:

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

El sistema de eventos que @validates usos también está disponible directamente. Se puede escribir una solución generalizada que une los validadores de su elección a los tipos de ser asignada:

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" 

Validación y coerción también se pueden construir en el nivel de tipo utilizando TypeDecorator, aunque esto es sólo cuando SQL se está emitiendo, tales como este ejemplo que coacciona cadenas UTF-8 a unicode:

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

+0

Gracias zzzeek. No había usado el sistema de eventos antes. Gran ejemplo que muestra dónde y cómo conectarse. – Nate

Cuestiones relacionadas