2010-02-23 4 views
6

in SQLAlchemy è possibile applicare la lunghezza massima della stringa di valore assegnata alla colonna mappata? Tutto quello che voglio è di generare un'eccezione se un valore di stringa assegnato è più lungo della lunghezza della colonna della tabella corrispondente di tipo STRING.SQLAlchemy - lunghezza massima della colonna

Grazie

+0

Si prega di indicare il codice che si sta utilizzando per definire il tavolo e la mappatura alla classe. AFAIK, il database dovrebbe generare un errore che si propaga di nuovo attraverso SQLAlchemy. Si prega di inviare il codice per fornire qualche suggerimento su ciò che stai provando ora. –

+0

@ S.Lott MySQL non controlla la lunghezza della stringa su insert/update. Tronca silenziosamente stringhe troppo lunghe. – codeape

risposta

6

E 'più facile per rinominare solo la colonna mappata e procura attraverso una proprietà:

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 

Si può facilmente scomporre la creazione di proprietà, e anche utilizzare un quadro di convalida generico come FormEncode .


Se avete bisogno di una soluzione specifica più SQLAlchemy e non mente utilizzando interfacce specifiche, quindi SQLAlchemy ha un meccanismo di estensione per catturare gli eventi su attributi. Un validatore usando che sarebbe simile a questa:

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 

Si potrebbe quindi utilizzare questa estensione impostando __sa_instrumentation_manager__ = InstallValidatorListeners su qualsiasi classe che si desidera convalidato. Puoi anche impostarlo sulla classe Base se vuoi che venga applicato a tutte le classi derivate da esso.

+0

Sì, risolve il problema, ma ho decine di tali colonne, quindi l'utilizzo della proprietà non è molto conveniente. La soluzione che utilizza il sistema di tipi SQLAlchemy sarebbe meglio. – honzas

+0

Ho aggiunto un esempio che può essere utilizzato per validatori specifici di sqlalchemy. –

+0

Sì, questo tipo di soluzione è l'ideale per me, grazie. – honzas

0

Ecco una versione aggiornata che si inserisce il sistema caso di versioni più recenti 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