Sqlalchemy 在表中定义多个自引用外键时出现问题

Sqlalchemy 在表中定义多个自引用外键时出现问题,sqlalchemy,Sqlalchemy,我这里有一些代码。我最近添加了这个root_id参数。这样做的目的是让我确定一个文件是否属于某个特定的项目,而不必将项目id FK添加到文件中(这将导致模型循环)。因此,我希望能够比较Project.directory和File.root。若为真,则该文件属于Project 但是,没有为文件自动生成File.root属性。我的理解是,在表foo implicit中定义FK foo_id会创建一个foo属性,您可以将foo对象分配给该属性。然后,在会话刷新时,foo_id被正确设置为指定对象的id

我这里有一些代码。我最近添加了这个root_id参数。这样做的目的是让我确定一个文件是否属于某个特定的项目,而不必将项目id FK添加到文件中(这将导致模型循环)。因此,我希望能够比较Project.directory和File.root。若为真,则该文件属于Project

但是,没有为文件自动生成File.root属性。我的理解是,在表foo implicit中定义FK foo_id会创建一个foo属性,您可以将foo对象分配给该属性。然后,在会话刷新时,foo_id被正确设置为指定对象的id。在下面的代码段中,这显然是针对Project.directory完成的,但为什么不是针对File.root

这显然与1)root_id是一个自引用FK的事实或2)文件和SQLAlchemy中有几个自引用FK的事实有关

我试过的东西

  • 试图定义“根”关系()-我认为这是错误的,不应该用连接表示
  • 尝试定义“根”列\u属性()-允许对已设置的根\u id属性进行读取访问,但分配给它时,不会反映回根\u id
我该怎么做我想做的事?谢谢

from sqlalchemy import create_engine, Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import backref, relationship, scoped_session, sessionmaker, column_property

Base = declarative_base()
engine = create_engine('sqlite:///:memory:', echo=True)
Session = scoped_session(sessionmaker(bind=engine))

class Project(Base):
   __tablename__ = 'projects'
   id = Column(Integer, primary_key=True)
   directory_id = Column(Integer, ForeignKey('files.id'))

class File(Base):
   __tablename__ = 'files'
   id = Column(Integer, primary_key=True)
   path = Column(String)
   parent_id = Column(Integer, ForeignKey('files.id'))
   root_id = Column(Integer, ForeignKey('files.id'))
   children = relationship('File', primaryjoin=id==parent_id, backref=backref('parent', remote_side=id), cascade='all')

Base.metadata.create_all(engine)

p = Project()
root = File()
root.path = ''

p.directory = root
f1 = File()
f1.path = 'test.txt'
f1.parent = root
f1.root = root

Session.add(f1)
Session.add(root)
Session.flush()
# do this otherwise f1 will be returned when calculating rf1
Session.expunge(f1)

rf1 = Session.query(File).filter(File.path == 'test.txt').one()
# this property does not exist
print rf1.root
我的理解是,在表foo implicit中定义FK foo_id会创建一个foo属性,您可以将foo对象分配给该属性

不,没有。在代码段中,它看起来就像是为
Project.directory
完成的,但是如果您查看正在回送的SQL语句,则
projects
表根本没有插入

因此,要使其正常工作,您需要添加以下两个关系:

class Project(Base):
    ...
    directory = relationship('File', backref='projects')

class File(Base):
    ...
    root = relationship('File', primaryjoin='File.id == File.root_id', remote_side=id)

啊,我明白你的意思,但我不认为这是我的问题。真正的项目/文件类实际上包含更多的内容。然而,我确实在生产代码中大量使用project.directory=File(),而且效果很好,所以确实发生了一些隐含的事情。。。明天我会尝试你的解决方案,但如果我所说的改变了你的答案,请随时更新。谢谢。我想这段代码中唯一的问题是我错过了一个会话。添加(p)。不过,看起来您的解决方案确实有效!我将在我的生产代码上测试它,并向您报告。:)谢谢,你提议的“根”关系成功了。关键是要理解,并非所有的关系都需要背景。(太令人困惑了。)标记为正确!!