使用SQLAlchemy处理组合键的关系

61 投票
1 回答
36702 浏览
提问于 2025-04-17 02:47

我有一个简单的模型,涉及作者和书籍,但我找不到办法把名字(firstName)和姓氏(lastName)组合成一个复合键,并在关系中使用它。有没有什么建议?

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:pass@library')
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'))            

1 个回答

111

问题在于,你把每个相关的列都单独定义成外键,但其实你并不想这样,你想要的是一个组合外键。Sqlalchemy对此的反应是(虽然不是很清楚),它不知道该用哪个外键(firstName还是lastName)。

解决办法是声明一个组合外键,这在声明式写法中有点麻烦,但其实还是挺明显的:

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

这里重要的是,ForeignKey 的定义不再出现在单独的列上,而是添加到了一个叫 __table_args__ 的类变量中,里面包含了一个 ForeignKeyConstraint。这样一来,在 Author.books 上定义的 relationship 就能正常工作了。

撰写回答