2009-06-24 8 views
1

J'ai une simple classe "Factures" avec un attribut "Nombre" qui doit être affecté par l'application lorsque l'utilisateur enregistre une facture. Il quelques contraintes:Attribut d'incrémentation automatique avec une logique personnalisée dans SQLAlchemy

1) l'application est un (mince) client-serveur un, donc quel que soit attribue le nombre doit regarder les collisions
2) Les factures a un attribut « version », donc je Je ne peux pas utiliser un simple champ auto-incrémenté SGBD

J'essaye de construire ceci en utilisant un type personnalisé qui donnerait un coup de pied dans chaque fois qu'une facture est enregistrée. Chaque fois que process_bind_param est appelé avec une valeur None, il appellera un singleton quelconque pour déterminer le numéro et éviter les collisions. Est-ce une solution décente? Quoi qu'il en soit, je vais avoir un problème .. Voici mon habitude Type:

class AutoIncrement(types.TypeDecorator): 
    impl = types.Unicode 

    def copy(self): 
     return AutoIncrement() 

    def process_bind_param(self, value, dialect): 
     if not value: 
      # Must find next autoincrement value 
      value = "1" # Test value :) 
     return value 

Mon problème est maintenant droit que lorsque j'enregistre une facture et AutoIncrement ensembles « 1 » comme valeur pour son numéro, l'instance facture ne obtenir mis à jour avec le nouveau nombre .. Est-ce prévu? Ai-je perdu quelque chose? Un grand merci pour votre temps!

(SQLA 0.5.3 sur Python 2.6, en utilisant postgreSQL 8,3)

Edit: Michael Bayer m'a dit que ce comportement est attendu, puisque TypeDecorators ne traitent pas avec des valeurs par défaut.

Répondre

3

Y a-t-il une raison particulière pour laquelle vous n'utilisez pas simplement un paramètre default= dans votre définition de colonne? (Cela peut être un appelable Python arbitraire).

def generate_invoice_number(): 
    # special logic to generate a unique invoice number 

class Invoice(DeclarativeBase): 
    __tablename__ = 'invoice' 
    number = Column(Integer, unique=True, default=generate_invoice_number) 
    ... 
+0

Aïe ne savais pas que vous pourriez utiliser là appelable, merci! Je vais essayer tout de suite :) – Joril

+0

Dites que votre callable par défaut renvoie le maximum de la colonne dans la base de données plus un. Y a-t-il un moyen d'affirmer qu'il n'y a pas de conditions de concurrence sans compter sur une erreur de la colonne étant unique? –

+0

Dans ce cas, il est préférable d'écrire votre valeur par défaut en tant qu'expression SQL inline. Ceci est couvert en détail dans la documentation SQLAlchemy à http://www.sqlalchemy.org/docs/05/metadata.html#pre-executed-and-inline-sql-expressions –

Questions connexes