Python 一对多+;炼金术中的一种关系?
我试图模拟以下情况:一个程序有许多版本,其中一个版本是当前版本(不一定是最新版本) 我现在就是这样做的:Python 一对多+;炼金术中的一种关系?,python,database,sqlalchemy,Python,Database,Sqlalchemy,我试图模拟以下情况:一个程序有许多版本,其中一个版本是当前版本(不一定是最新版本) 我现在就是这样做的: class Program(Base): __tablename__ = 'programs' id = Column(Integer, primary_key=True) name = Column(String) current_version_id = Column(Integer, ForeignKey('program_versions.id'))
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')
但是我得到了一个错误:无法确定relationship Program.versions上的父/子表之间的联接条件-有多个外键路径链接这些表。指定'foreign_keys'参数,提供应计为包含对父表的外键引用的列的列表
但是我应该为“Program.versions”关系提供什么外键呢?有没有更好的方法来模拟这种情况?这种设计并不理想;通过让两个表相互引用,您无法有效地插入其中一个表,因为另一个表中所需的外键将不存在。中的一个可能解决方案在的选定答案中概述 ,但我将在这里对其进行总结/详细说明 更好的建模方法可能是引入第三个表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
字段添加到此表中可以减轻其他两个表跟踪货币的负担,尽管每个程序保持一个当前版本可能需要一些触发操作
嗯 这样的循环依赖是解决这个问题的一个非常有效的方法 要解决外键问题,需要显式提供
外键
参数
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, ...)
...