簡體   English   中英

SQLAlchemy中一對多+一個關系?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM