2010-02-23 38 views
6

¿es posible en SQLAlchemy imponer la longitud de cadena máxima del valor asignado a la columna asignada? Todo lo que quiero es generar una excepción si el valor de una cadena asignada es más largo que la longitud de la columna de la tabla correspondiente de tipo STRING.SQLAlchemy: longitud máxima de columna

Gracias

+0

Por favor indicar el código que está utilizando para definir la tabla y la asignación a la clase. AFAIK, la base de datos debería generar un error que se propaga a través de SQLAlchemy. Por favor, publique el código para proporcionar una pista sobre lo que está intentando ahora. –

+0

@ S.Lott MySQL no comprueba la longitud de la cadena en insertar/actualizar. Silenciosamente trunca cadenas que son demasiado largas. – codeape

Respuesta

6

Es más fácil simplemente cambiar el nombre de la columna asignada y el proxy a través de una propiedad:

class Something(Base): 
    ... 
    _foo = Column('foo', String(123)) 

    @property 
    def foo(self): 
     return self._foo 

    @foo.setter 
    def foo(self, value): 
     if len(value) > _foo.type.length: 
      raise Exception("Value too long") 
     self._foo = value 

Usted puede factorizar fácilmente la creación de propiedad, e incluso utilizar un marco de validación genérico como formencode .


Si necesita una solución específica más SQLAlchemy y no les importa usar interfaces específicas, entonces SQLAlchemy tiene un mecanismo de extensión para capturar eventos en atributos. Un validador usando que sería algo como esto:

from sqlalchemy.orm.interfaces import AttributeExtension, InstrumentationManager 
from sqlalchemy.orm import ColumnProperty 

class InstallValidatorListeners(InstrumentationManager): 
    def post_configure_attribute(self, class_, key, inst): 
     """Add validators for any attributes that can be validated.""" 
     prop = inst.prop 
     # Only interested in simple columns, not relations 
     if isinstance(prop, ColumnProperty) and len(prop.columns) == 1: 
      col = prop.columns[0] 
      # if we have string column with a length, install a length validator 
      if isinstance(col.type, String) and col.type.length: 
       inst.impl.extensions.insert(0, LengthValidator(col.type.length)) 

class ValidationError(Exception): 
    pass 

class LengthValidator(AttributeExtension): 
    def __init__(self, max_length): 
     self.max_length = max_length 

    def set(self, state, value, oldvalue, initiator): 
     if len(value) > self.max_length: 
      raise ValidationError("Length %d exceeds allowed %d" % 
           (len(value), self.max_length)) 
     return value 

A continuación, utilizar esta extensión mediante el establecimiento de __sa_instrumentation_manager__ = InstallValidatorListeners en cualquier clase que desea validado. También puede configurarlo en la clase Base si desea que se aplique a todas las clases derivadas de él.

+0

Sí, resuelve el problema, pero tengo decenas de tales columnas, por lo que usar la propiedad no es muy conveniente. La solución que usa el sistema de tipo SQLAlchemy sería mejor. – honzas

+0

Agregué un ejemplo que se puede usar para validadores específicos de sqlalchemy. –

+0

Sí, este tipo de solución es ideal para mí, gracias. – honzas

0

Aquí es una versión actualizada que se ajusta al sistema de eventos de versiones más recientes SQLAlchemy:

class InstallValidatorListeners(InstrumentationManager): 
    def post_configure_attribute(self, class_, key, inst): 
     """Add validators for any attributes that can be validated.""" 
     prop = inst.prop 
     # Only interested in simple columns, not relations 
     if isinstance(prop, ColumnProperty) and len(prop.columns) == 1: 
      col = prop.columns[0] 
      if isinstance(col.type, String) and col.type.length: 
       sqlalchemy.event.listen(
        getattr(class_, key), 'set', LengthValidator(col.type.length), retval=True) 


class ValidationError(Exception): 
    pass 


class LengthValidator(AttributeExtension): 
    def __init__(self, max_length): 
     self.max_length = max_length 

    def __call__(self, state, value, oldvalue, initiator): 
     if len(value) > self.max_length: 
      raise ValidationError(
       "Length %d exceeds allowed %d" % (len(value), self.max_length)) 
     return value