270 votes

sqlalchemy unique sur plusieurs colonnes

Disons que j'ai une classe qui représente des lieux. Les emplacements "appartiennent" aux clients. Les emplacements sont identifiés par un code unicode de 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 deux avoir un emplacement appelé "principal" mais aucun ne peut avoir deux emplacements appelés "principal".

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

456voto

van Points 18052

Extrait du documentation de la Column :

unique - Lorsque Vrai, indique que cette colonne contient une contrainte unique unique, ou si indice est également vrai, indique que l'index doit être créé avec l'indicateur unique. Pour spécifier plusieurs colonnes dans dans la contrainte/l'index ou pour spécifier un nom explicite, utilisez l'attribut UniqueConstraint o Index de manière explicite.

Comme ces éléments appartiennent à une table et non à une classe mappée, on les déclare dans la définition de la table ou, si l'on utilise le mode déclaratif comme dans le cas de l'option __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'),
                     )

1 votes

Je rencontre le même problème, mais l'utilisation de 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 ?

1 votes

@swdev : quel SGBDR utilisez-vous ?

0 votes

J'utilise PostgreSQL. Y a-t-il un problème à ce niveau ?

49voto

joash Points 186
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))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X