Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 一对多+;炼金术中的一种关系?_Python_Database_Sqlalchemy - Fatal编程技术网

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, ...)
    ...