sqlalchemy único en múltiples columnas

174

Digamos que tengo una clase que representa ubicaciones. Las ubicaciones "pertenecen" a los clientes. Las ubicaciones se identifican mediante un código Unicode de 10 caracteres. El "código de ubicación" debe ser único entre las ubicaciones de un 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))

Entonces, si tengo dos clientes, el cliente "123" y el cliente "456". Ambos pueden tener una ubicación llamada "main" pero ninguno podría tener dos ubicaciones llamadas main.

Puedo manejar esto en la lógica de negocios, pero quiero asegurarme de que no haya forma de agregar fácilmente el requisito en sqlalchemy. La opción unique = True parece funcionar solo cuando se aplica a un campo específico y causaría que toda la tabla solo tenga un código único para todas las ubicaciones.

Ominus
fuente

Respuestas:

298

Extracto de la documentación de Column:

unique : cuando es True, indica que esta columna contiene una restricción única, o si el índice también es True, indica que el índice debe crearse con la bandera única. Para especificar varias columnas en la restricción / índice o para especificar un nombre explícito, use las construcciones UniqueConstraint o Index explícitamente.

Como estos pertenecen a una tabla y no a una clase asignada, se declaran aquellos en la definición de la tabla, o si se usa declarativa como en __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'),
                     )
camioneta
fuente
También enfrento el mismo problema, pero usar UniqueConstraint no me ayudó. Después de intentar con Index ('...'), obtengo una restricción única. ¿Hay alguna explicación con este comportamiento?
swdev
1
@swdev: ¿qué RDBMS usas?
van
3
Gracias, pero mi pregunta fue: ¿utilizó SA (y Flask) para crear un esquema de base de datos, o lo creó por separado?
van
1
¿Por qué es el .c. ¿usado?
Smiley
1
@Smiley .c.es un atajo 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))
joash
fuente
1
Debe ser __table_args__ = (db.UniqueConstraint('customer_id', 'location_code'),), no olvides la coma al final.
bertdida