sqlalchemy unikalne w wielu kolumnach

174

Powiedzmy, że mam klasę reprezentującą lokalizacje. Lokalizacje „należą” do klientów. Lokalizacje są identyfikowane za pomocą 10-znakowego kodu Unicode. „Kod lokalizacji” powinien być niepowtarzalny wśród lokalizacji dla określonego klienta.

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

Więc jeśli mam dwóch klientów, klienta „123” i klienta „456”. Oba mogą mieć lokalizację zwaną „główną”, ale żadna z nich nie może mieć dwóch lokalizacji zwanych główną.

Potrafię sobie z tym poradzić w logice biznesowej, ale chcę się upewnić, że nie ma możliwości łatwego dodania wymagania w sqlalchemy. Opcja unique = True działa tylko wtedy, gdy zostanie zastosowana do określonego pola i spowodowałaby, że cała tabela miałaby tylko unikalny kod dla wszystkich lokalizacji.

Ominus
źródło

Odpowiedzi:

298

Wyciąg z dokumentacji z Column:

unique - Gdy True, wskazuje, że ta kolumna zawiera unikalne ograniczenie lub jeśli indeks ma również wartość True, wskazuje, że indeks powinien zostać utworzony z unikalną flagą. Aby określić wiele kolumn w ograniczeniu / indeksie lub określić jawną nazwę, należy jawnie użyć konstrukcji UniqueConstraint lub Index .

Ponieważ należą one do tabeli, a nie do zamapowanej klasy, deklaruje się je w definicji tabeli lub w przypadku użycia deklaratywnego, jak w __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'),
                     )
awangarda
źródło
Mam ten sam problem, ale użycie UniqueConstraint mi nie pomogło. Po wypróbowaniu indeksu („...”) otrzymuję unikalne ograniczenie. Czy jest jakieś wyjaśnienie tego zachowania?
swdev
1
@swdev: którego RDBMS używasz?
van
3
Dzięki, ale moje pytanie brzmiało: czy użyłeś SA (i Flask) do stworzenia schematu bazy danych, czy też stworzyłeś go osobno?
van
1
Dlaczego .c. używany?
Smiley
1
@Smiley .c.to skrót do.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
źródło
1
Musi być __table_args__ = (db.UniqueConstraint('customer_id', 'location_code'),), nie zapomnij o przecinku na końcu.
bertdida