2011-09-21 9 views
30

Ho questo semplice modello di Autore - Libri e non riesco a trovare un modo per rendere firstName e lastName una chiave composta e usarla in relazione. Qualche idea?Relazioni su tasti compositi usando 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'))    

risposta

52

Il problema è che si è definito ciascuna delle colonne dipendenti come chiavi esterne separatamente, quando questo non è in realtà ciò che si intende, è ovviamente vuole una chiave esterna composita. Sqlalchemy risponde a questo dicendo (in un modo non molto chiaro), che non può indovinare quale chiave esterna usare (firstName o lastName).

La soluzione, dichiarando una chiave esterna composta, è un po 'goffo in dichiarativa, ma ancora abbastanza ovvia:

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]), 
         {}) 

La cosa importante è che i ForeignKey definizioni sono spariti dalle singole colonne, ed un ForeignKeyConstraint viene aggiunto a una variabile di classe __table_args__. Con questo, il relationship definito su Author.books funziona correttamente.

+2

I [docs] (http://docs.sqlalchemy.org/en/rel_0_9/core/constraints.html?highlight=check#metadata-foreignkeys) includono ulteriori chiarimenti ed esempi: È importante notare che 'ForeignKeyConstraint 'è l'unico modo per definire una chiave esterna composita. Mentre potremmo anche aver posizionato singoli oggetti 'ForeignKey' su entrambe [...] le colonne, SQLAlchemy non sarebbe stato consapevole del fatto che questi due valori dovrebbero essere accoppiati - sarebbero due vincoli di chiave esterna singoli invece di una singola chiave estranea composta. due colonne. – iled