反向引用类属性

9 投票
2 回答
1935 浏览
提问于 2025-04-17 16:10

如何在不通过会话进行一些查询的情况下初始化映射器的反向引用?

举个例子,我有两个模型,分别叫做“Client”(客户)和“Subject”(主题),在下面的代码中:

Base = declarative_base()

class Client(Base):
    __tablename__ = "clients"

    id = Column(Integer, primary_key=True)
    created = Column(DateTime, default=datetime.datetime.now)
    name = Column(String)

    subjects = relationship("Subject",  cascade="all,delete",
        backref=backref("client"))


class Subject(Base):
    __tablename__ = "subjects"

    id = Column(Integer, primary_key=True)
    client_id = Column(Integer, ForeignKey(Client.id, ondelete='CASCADE'))

然后,在我代码的某个地方,我想这样获取类Subject的反向引用client,但这会引发一个异常:

>>> Subject.client
AttributeError: type object 'Subject' has no attribute 'client'

在对Client进行查询后,比如:

>>> session.query(Client).first()
>>> Subject.client
<sqlalchemy.orm.attributes.InstrumentedAttribute at 0x43ca1d0>

属性client是在对相关模型(映射器)进行查询后创建的。
我不想进行这样的“预热”查询!

2 个回答

6

因为 SQLAlchemy 使用了元类,所以在另一个类上创建反向引用的代码,直到你至少创建了一个 Client 类的实例之前,是不会运行的。

解决这个问题的方法很简单:创建一个 Client() 实例,然后再把它丢掉:

>>> Subject.client
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Subject' has no attribute 'client'
>>> Client()
<__main__.Client object at 0x104bdc690>
>>> Subject.client
<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x104be9e10>

或者使用这个 configure_mappers 工具函数:

from sqlalchemy.orm import configure_mappers

它会扫描你的模型,查找这样的引用并初始化它们。实际上,创建任何一个实例都会在后台调用这个方法。

13

另外,你可以使用:

from sqlalchemy.orm import configure_mappers

configure_mappers()

这样做的好处是,它可以一步到位地为你所有的模型创建所有的反向引用。

撰写回答