2010-02-23 4 views
6

est-il possible dans SQLAlchemy d'imposer la longueur de chaîne maximale de la valeur affectée à la colonne mappée? Tout ce que je veux, c'est lever une exception si une valeur de chaîne affectée est plus longue que la longueur de la colonne de table correspondante de type STRING.SQLAlchemy - longueur de colonne maximale

Merci

+0

S'il vous plaît indiquer le code que vous utilisez pour définir la table et la mise en correspondance à votre classe. AFAIK, la base de données devrait déclencher une erreur qui se propage à travers SQLAlchemy. Veuillez poster du code pour donner un indice sur ce que vous essayez maintenant. –

+0

@ S.Lott MySQL ne vérifie pas la longueur de la chaîne lors de l'insertion/mise à jour. Il tronque silencieusement les chaînes qui sont trop longues. – codeape

Répondre

6

Il est plus facile de renommer simplement la colonne mappée et proxy à travers une propriété:

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 

Vous pouvez facilement factoriser la création de la propriété, et même utiliser un cadre de validation générique comme formencode .


Si vous avez besoin d'une solution spécifique plus SQLAlchemy et ne me dérange pas l'utilisation d'interfaces spécifiques, puis SQLAlchemy a un mécanisme d'extension pour capturer les événements sur les attributs. Un validateur utilisant qui ressemblerait à quelque chose comme ceci:

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 

Vous pouvez ensuite utiliser cette extension en mettant __sa_instrumentation_manager__ = InstallValidatorListeners sur une classe que vous voulez valider. Vous pouvez également le définir sur la classe Base si vous souhaitez qu'il s'applique à toutes les classes dérivées.

+0

Oui, il résout le problème, mais j'ai des dizaines de colonnes, donc l'utilisation de la propriété n'est pas très pratique. La solution qui utilise le système de type SQLAlchemy serait meilleure. – honzas

+0

J'ai ajouté un exemple qui peut être utilisé pour les validateurs spécifiques de sqlalchemy. –

+0

Oui, ce type de solution est idéal pour moi, merci. – honzas

0

Voici une version mise à jour qui correspond au système d'événements de nouvelles versions 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 
Questions connexes