2011-09-21 18 views
30

Mam ten prosty model autora - książki i nie mogę znaleźć sposobu na zrobienie firstName i lastName klucza złożonego i użycie go w relacji. Jakieś pomysły?Relacje na klucze złożone przy użyciu sqlalchemy

from sqlalchemy import create_engine, ForeignKey, Column, String, Integer 
from sqlalchemy.orm import relationship, sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 
engine = create_engine('mssql://user:[email protected]') 
engine.echo = True 
session = sessionmaker(engine)() 

class Author(Base): 
    __tablename__ = 'authors' 
    firstName = Column(String(20), primary_key=True) 
    lastName = Column(String(20), primary_key=True) 
    books = relationship('Book', backref='author') 

class Book(Base): 
    __tablename__ = 'books' 
    title = Column(String(20), primary_key=True) 
    author_firstName = Column(String(20), ForeignKey('authors.firstName')) 
    author_lastName = Column(String(20), ForeignKey('authors.lastName'))    

Odpowiedz

52

Problem polega na tym, że każdy z definicją zależnych kolumn jako kluczy obcych oddzielnie, kiedy to nie jest naprawdę to, co zamierzam, ty oczywiście chcą kompozytowy klucz obcy. Sqlalchemy odpowiada na to, mówiąc (w niezbyt jasny sposób), że nie może odgadnąć, który klucz obcy ma używać (firstName lub lastName).

Rozwiązanie, deklarując kompozytowy klucz obcy, jest odrobinę niezdarny w deklaratywny, ale nadal dość oczywiste:

class Book(Base): 
    __tablename__ = 'books' 
    title = Column(String(20), primary_key=True) 
    author_firstName = Column(String(20)) 
    author_lastName = Column(String(20)) 
    __table_args__ = (ForeignKeyConstraint([author_firstName, author_lastName], 
              [Author.firstName, Author.lastName]), 
         {}) 

Ważną rzeczą jest to, że definicje ForeignKey zniknęły z poszczególnych kolumn, a ForeignKeyConstraint jest dodawany do zmiennej klasy __table_args__. Dzięki temu relationship zdefiniowany na Author.books działa poprawnie.

+2

[docs] (http://docs.sqlalchemy.org/en/rel_0_9/core/constraints.html?highlight=check#metadata-foreignkeys) zawiera dodatkowe wyjaśnienia i przykłady: Należy pamiętać, że 'ForeignKeyConstraint 'jest jedynym sposobem zdefiniowania złożonego klucza obcego. Chociaż moglibyśmy umieścić indywidualne obiekty 'ForeignKey' w obu kolumnach [...], SQLAlchemy nie byłby świadomy, że te dwie wartości powinny być sparowane ze sobą - byłyby to dwa indywidualne ograniczenia obce zamiast pojedynczego złożonego odniesienia do klucza obcego. dwie kolumny. – iled