[英]One to many + one relationship in SQLAlchemy?
我試圖模擬以下情況:程序有許多版本,其中一個版本是當前版本(不一定是最新版本)。
這就是我現在這樣做的方式:
class Program(Base):
__tablename__ = 'programs'
id = Column(Integer, primary_key=True)
name = Column(String)
current_version_id = Column(Integer, ForeignKey('program_versions.id'))
current_version = relationship('ProgramVersion', foreign_keys=[current_version_id])
versions = relationship('ProgramVersion', order_by='ProgramVersion.id', back_populates='program')
class ProgramVersion(Base):
__tablename__ = 'program_versions'
id = Column(Integer, primary_key=True)
program_id = Column(Integer, ForeignKey('programs.id'))
timestamp = Column(DateTime, default=datetime.datetime.utcnow)
program = relationship('Filter', foreign_keys=[program_id], back_populates='versions')
但后來我得到錯誤:無法確定關系Program.versions上的父/子表之間的連接條件 - 有多個鏈接表的外鍵路徑。 指定'foreign_keys'參數,提供應列為包含對父表的外鍵引用的列的列表。
但是我應該為“Program.versions”關系提供什么外鍵? 有沒有更好的方法來模擬這種情況?
這種設計並不理想; 通過讓兩個表相互引用,您無法有效地插入到任一個表中,因為另一個表中所需的外鍵將不存在。 在這個問題的選定答案中概述的一個可能的解決方案與microsoft sqlserver有關 ,但我將在此總結/詳述。
對此進行建模的更好方法可能是引入第三個表VersionHistory,並消除對其他兩個表的外鍵約束。
class VersionHistory(Base):
__tablename__ = 'version_history'
program_id = Column(Integer, ForeignKey('programs.id'), primary_key=True)
version_id = Column(Integer, ForeignKey('program_version.id'), primary_key=True)
current = Column(Boolean, default=False)
# I'm not too familiar with SQLAlchemy, but I suspect that relationship
# information goes here somewhere
這消除了您在當前實現中創建的循環關系。 然后,您可以按程序查詢此表,並接收程序的所有現有版本等。由於此表中的復合主鍵,您可以訪問任何特定的程序/版本組合。 向該表添加current
字段需要跟蹤其他兩個表的貨幣負擔,盡管每個程序保持一個當前版本可能需要一些觸發器體操。
HTH!
像這樣的循環依賴是這個問題的完美有效的解決方案。
要修復外鍵問題,需要顯式提供foreign_keys
參數。
class Program(Base):
...
current_version = relationship('ProgramVersion', foreign_keys=current_version_id, ...)
versions = relationship('ProgramVersion', foreign_keys="ProgramVersion.program_id", ...)
class ProgramVersion(Base):
...
program = relationship('Filter', foreign_keys=program_id, ...)
您會發現當您執行create_all()
,SQLAlchemy無法創建表,因為每個表都有一個依賴於另一個列中的列的外鍵。 SQLAlchemy提供了一種通過對其中一個表使用ALTER
語句來打破此循環依賴關系的方法:
class Program(Base):
...
current_version_id = Column(Integer, ForeignKey('program_versions.id', use_alter=True, name="fk_program_current_version_id"))
...
最后,您會發現當您向會話添加完整的對象圖時,SQLAlchemy無法發出INSERT
語句,因為每行的值都取決於另一行的未知主鍵。 SQLAlchemy提供了一種通過為其中一列發出UPDATE
來打破此循環依賴關系的方法:
class Program(Base):
...
current_version = relationship('ProgramVersion', foreign_keys=current_version_id, post_update=True, ...)
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.