10

我有一堂课:

class ExampleClass(Base):
    __tablename__ = 'chart'
    id = Column(Integer, primary_key=True)
    element_id = Column(Integer, ForeignKey('anotherTable.id'))
    element = relationship(AnotherClass)
    element2_id = Column(Integer, ForeignKey('anotherTable2.id'))
    element2 = relationship(AnotherClass2)

我想基于element_idand进行查找element2_id

class ExampleClass(Base):
    ...
    def get_with_element2(self, element2):
        return session.query(ExampleClass).\
                       filter_by(element_id = self.element_id,
                                 element2_id = element2.id).first()

我发现的问题是,如果我实例化一个新ExampleClass对象并将其分配给,则不会设置element该字段:element_id

a = ExampleClass(element=element_obj)
a.element_id => None

我该如何解决这个问题?处理这种情况的最佳方法是什么?

4

1 回答 1

12

首先,下面的所有示例都假设您的ExampleClass实例至少处于挂起状态,如果不是“持久”状态(即session.add(a))。换句话说,如果您尚未与 a 交互Session并且尚未将ExampleClass对象添加到其中,那么您将不会获得 的任何数据库级行为relationship(),其中维护外键列值是主要功能。您当然可以自由地直接进行此作业:

a = ExampleClass(element_id=element_obj.id)

但这显然没有利用relationship()构造提供的自动化。

外键属性的分配relationship()发生在刷新期间,这是一个仅在需要与数据库交互时发生的过程,例如在使用 发出 SQL 语句session.query()之前或在使用 完成事务之前session.commit()

通常,这里的理念relationship()是您只处理“元素”和“元素2”属性,而让外键属性在幕后处理。您可以这样编写查询:

session.query(ExampleClass).\
     filter_by(element=self.element).\
     filter_by(element2=element2)

ORM 将进行比较,例如SomeClass.somerelationship=someobject并将其转换为外键表达式SomeClass.some_fk=some_id,但不同之处在于,“some_id”的最终值的评估被推迟到执行查询之前的右侧。在执行查询之前,Query()对象会告诉Session“自动刷新”,这将产生插入行以及分配给对象属性ExampleClass的主键标识符的效果。element_objelement_idExampleClass

您可以在仍然使用这样的 FK 属性的同时获得类似的效果,但这主要是为了了解它是如何工作的:

session.query(ExampleClass).\
   filter_by(element_id=bindparam(callable_=lambda: self.element_id)).\
   filter_by(element2_id=element2.id)

或者更明确地说,先进行冲洗:

session.flush()
session.query(ExampleClass).\
   filter_by(element_id=self.element_id).\
   filter_by(element2_id=element2.id)

因此,在您想要element_id明确引用外键属性的程度上,您还需要relationship()明确地为您做的事情。如果您严格处理对象实例和relationship()-bound 属性,并保留典型的默认值(如autoflush启用),它通常会做“正确的事情”并确保属性在需要时准备就绪。

于 2012-12-25T15:52:37.460 回答