sqlalchemy exclusivo em várias colunas


174

Digamos que eu tenho uma classe que representa locais. Os locais "pertencem" aos clientes. Os locais são identificados por um código de 10 caracteres unicode. O "código do local" deve ser único entre os locais de um cliente específico.

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

Então, se eu tiver dois clientes, o cliente "123" e o cliente "456". Ambos podem ter um local chamado "principal", mas nenhum deles poderia ter dois locais chamados principal.

Eu posso lidar com isso na lógica de negócios, mas quero garantir que não haja como adicionar facilmente o requisito no sqlalchemy. A opção unique = True parece funcionar apenas quando aplicada a um campo específico e faria com que a tabela inteira tivesse apenas um código exclusivo para todos os locais.

Respostas:


298

Extrato da documentação do Column:

unique - Quando True, indica que esta coluna contém uma restrição exclusiva ou, se o índice também for True, indica que o Índice deve ser criado com o sinalizador exclusivo. Para especificar várias colunas na restrição / índice ou para especificar um nome explícito, use as construções UniqueConstraint ou Index explicitamente.

Como estes pertencem a uma tabela e não a uma classe mapeada, declara-se aqueles na definição da tabela ou se estiver usando declarativo como em __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'),
                     )

Também enfrento o mesmo problema, mas o uso do UniqueConstraint não me ajudou. Depois de tentar com Índice ('...'), recebo uma restrição exclusiva. Existe alguma explicação para esse comportamento?
10133 swdev

1
@swdev: qual RDBMS você usa?
van

3
Obrigado, mas minha pergunta foi: você usou o SA (e o Flask) para criar um esquema de banco de dados ou criou separadamente?
van

1
Por que o .c. usava?
Smiley

1
@ Smiley .c.é um atalho para.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))

1
Deve ser __table_args__ = (db.UniqueConstraint('customer_id', 'location_code'),), não esqueça a vírgula no final.
bertdida 5/07
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.