我这里有一些代码。我最近添加了这个root_id参数。这样做的目的是让我确定一个文件是否属于一个特定的项目而不必将project_id FK添加到File中(这将导致模型循环。)因此,我希望能够将Project.directory与File进行比较。 。根。如果是这样,则File属于Project。
但是,File.root属性不是为File自动生成的。我的理解是将FK foo_id定义到表Foo中隐式创建了一个foo属性,您可以为其指定一个Foo对象。然后,在会话刷新时,foo_id被正确设置为指定对象的id。在下面的代码段中,显然正在为Project.directory完成,但为什么不为File.root?
看起来它似乎与1))root_id是自引用FK或2)事实上在File和SQLAlchemy中有几个自引用FK这一事实有所混淆。
我尝试过的事情。
我该怎样做我想做的事情?谢谢!
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
答案 0 :(得分:2)
我的理解是将FK foo_id定义到表Foo中隐式创建了一个foo属性,您可以为其指定一个Foo对象。
不,它没有。在代码片段中,看起来它只是为Project.directory
完成,但是如果你看一下被回显的SQL语句,那么projects
表就没有INSERT了。
因此,要使其正常工作,您需要添加以下两种关系:
class Project(Base):
...
directory = relationship('File', backref='projects')
class File(Base):
...
root = relationship('File', primaryjoin='File.id == File.root_id', remote_side=id)