sqlalchemy unique sur plusieurs colonnes

174

Disons que j'ai une classe qui représente des emplacements. Les emplacements «appartiennent» aux clients. Les emplacements sont identifiés par un code Unicode à 10 caractères. Le «code d'emplacement» doit être unique parmi les emplacements d'un client spécifique.

The two below fields in combination should be unique
customer_id = Column(Integer,ForeignKey('customers.customer_id')
location_code = Column(Unicode(10))

Donc, si j'ai deux clients, le client "123" et le client "456". Ils peuvent tous les deux avoir un emplacement appelé "main" mais aucun des deux ne peut avoir deux emplacements appelés main.

Je peux gérer cela dans la logique métier, mais je veux m'assurer qu'il n'y a aucun moyen d'ajouter facilement l'exigence dans sqlalchemy. L'option unique = True semble ne fonctionner que lorsqu'elle est appliquée à un champ spécifique et cela ferait en sorte que la table entière n'ait qu'un code unique pour tous les emplacements.

Ominus
la source

Réponses:

298

Extrait de la documentation du Column:

unique - Lorsque True, indique que cette colonne contient une contrainte unique, ou si l' index est également True, indique que l'index doit être créé avec l'indicateur unique. Pour spécifier plusieurs colonnes dans la contrainte / index ou pour spécifier un nom explicite, utilisez explicitement les constructions UniqueConstraint ou Index .

Comme ceux-ci appartiennent à une table et non à une classe mappée, on les déclare dans la définition de la table, ou si on utilise déclarative comme dans le __table_args__:

# version1: table definition
mytable = Table('mytable', meta,
    # ...
    Column('customer_id', Integer, ForeignKey('customers.customer_id')),
    Column('location_code', Unicode(10)),

    UniqueConstraint('customer_id', 'location_code', name='uix_1')
    )
# or the index, which will ensure uniqueness as well
Index('myindex', mytable.c.customer_id, mytable.c.location_code, unique=True)


# version2: declarative
class Location(Base):
    __tablename__ = 'locations'
    id = Column(Integer, primary_key = True)
    customer_id = Column(Integer, ForeignKey('customers.customer_id'), nullable=False)
    location_code = Column(Unicode(10), nullable=False)
    __table_args__ = (UniqueConstraint('customer_id', 'location_code', name='_customer_location_uc'),
                     )
van
la source
Je suis également confronté au même problème, mais utiliser UniqueConstraint ne m'a pas aidé. Après avoir essayé avec Index ('...'), j'obtiens une contrainte unique. Y a-t-il une explication à ce comportement?
swdev
1
@swdev: quel SGBDR utilisez-vous?
van du
3
Merci, mais ma question était: avez-vous utilisé SA (et Flask) pour créer un schéma DB, ou l'avez-vous créé séparément?
van
1
Pourquoi le .c. utilisé?
Smiley
1
@Smiley .c.est un raccourci vers.columns.
van
7
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class Location(Base):
      __table_args__ = (
        # this can be db.PrimaryKeyConstraint if you want it to be a primary key
        db.UniqueConstraint('customer_id', 'location_code'))
      customer_id = Column(Integer,ForeignKey('customers.customer_id')
      location_code = Column(Unicode(10))
Joash
la source
1
Doit être __table_args__ = (db.UniqueConstraint('customer_id', 'location_code'),), n'oubliez pas la virgule à la fin.
bertdida