在父关系中由 backref= 创建时无法识别子属性
我有几个具有以下模式的sqlalchemy模型,
class CM(Base):
__tablename__ = "cm"
id = Column("id", Integer(), primary_key=True)
status = Column("status", String(32), nullable=False)
hostname = Column("hostname", String(128), nullable=False)
faults = relationship(
"Fault", backref="cm", lazy="selectin", cascade="all, delete-orphan"
)
class Fault(Base):
__tablename__ = "fault"
id = Column("id", Integer, primary_key=True)
cm_id = Column(
Integer,
ForeignKey("cm.id", ondelete="CASCADE"),
index=True,
nullable=False,
)
component = Column("component", Text(255))
当我选择
父表(即一对多关系的一侧)时, 在我的例子中是CM
一切正常
select(CM).filter(CM.faults.any(component="fake"))
<sqlalchemy.sql.selectable.Select object at 0x105187910>
如果我尝试选择其他方式,它似乎会失败
select(Fault).filter(Fault.cm.has(hostname="fake"))
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: type object 'Fault' has no attribute 'cm'
事实证明,如果相关列 cm
以某种方式加载,则上面的 select 开始工作,所以如果我做这样的事情
session.query(Fault).filter(Fault.cm.has(hostname="fake"))
<sqlalchemy.orm.query.Query object at 0x10da57fd0>
select(Fault).filter(Fault.cm.has(hostname="fake"))
<sqlalchemy.sql.selectable.Select object at 0x10da669d0>
或者甚至这样
select(CM).filter(CM.faults.any(component="fake"))
<sqlalchemy.sql.selectable.Select object at 0x1077a39d0>
select(Fault).filter(Fault.cm.has(hostname="fake"))
<sqlalchemy.sql.selectable.Select object at 0x1077bb510>
我的猜测是 select
无法在关系的许多方面加载相关字段,但我不确定如何修复。
事实上,我还尝试将 backref 列重命名为 cm
中的其他内容,这样它就不会与表名冲突,甚至这也不起作用。
我可以使用 sqlalchemy 1.x 风格的 query
API 使用 session.query
来解决此问题,但由于 query
API 将从 2.x 中删除有没有办法让它与select
一起工作。
I have couple of sqlalchemy models with the following schemas
class CM(Base):
__tablename__ = "cm"
id = Column("id", Integer(), primary_key=True)
status = Column("status", String(32), nullable=False)
hostname = Column("hostname", String(128), nullable=False)
faults = relationship(
"Fault", backref="cm", lazy="selectin", cascade="all, delete-orphan"
)
class Fault(Base):
__tablename__ = "fault"
id = Column("id", Integer, primary_key=True)
cm_id = Column(
Integer,
ForeignKey("cm.id", ondelete="CASCADE"),
index=True,
nullable=False,
)
component = Column("component", Text(255))
When I select
the parent table(i.e one side of one-to-many relation) which in my case is CM
everything works fine
select(CM).filter(CM.faults.any(component="fake"))
<sqlalchemy.sql.selectable.Select object at 0x105187910>
If I try selecting the other way around it seems to fail
select(Fault).filter(Fault.cm.has(hostname="fake"))
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: type object 'Fault' has no attribute 'cm'
It turns out that if the related column cm
is loaded in some way then the above select
starts to work, so if I do something like this
session.query(Fault).filter(Fault.cm.has(hostname="fake"))
<sqlalchemy.orm.query.Query object at 0x10da57fd0>
select(Fault).filter(Fault.cm.has(hostname="fake"))
<sqlalchemy.sql.selectable.Select object at 0x10da669d0>
Or even this
select(CM).filter(CM.faults.any(component="fake"))
<sqlalchemy.sql.selectable.Select object at 0x1077a39d0>
select(Fault).filter(Fault.cm.has(hostname="fake"))
<sqlalchemy.sql.selectable.Select object at 0x1077bb510>
My guess is select
is not able to load the related field on many side of the relationship, but I am not sure how do I fix.
In fact I also tried renaming the backref column to something else from cm
so that it doesn't conflict with table name and even that did not work.
I can use the sqlalchemy 1.x style query
API using session.query
to workaround this but since query
API will be removed from 2.x is there a way to make it work with select
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在
CM
类中指定relationship("Fault", backref="cm", …)
将“自动”在Fault
类,但该属性不会在声明(或导入)模型时立即创建。如果我们做的第一件事是然后我们得到错误
子类中的魔法通常会在第一次实例化父类时发生
另一种选择是在执行任何实际工作之前调用
configure_mappers()
然而,backref 现在被视为遗留,因此首选方法是使用
back_populates=
而不是backref=
并显式声明属性两个班级:Specifying
relationship("Fault", backref="cm", …)
in theCM
class will "automagically" create acm
attribute in theFault
class, but that attribute does not get created immediately on declaring (or importing) the models. If the first thing we do isthen we get the error
The magic in the child class normally happens the first time that the parent class is instantiated
Another option is to call
configure_mappers()
before doing any real workHowever, backref is now considered legacy so the preferred approach is to use
back_populates=
instead ofbackref=
and explicitly declare the attributes in both classes: