Django模型:保留外键上的对象标识

Django模型:保留外键上的对象标识,django,django-models,Django,Django Models,Django的ORM(版本1.2.3)在来回跟踪外键时不保留标识。最好用一个例子来说明这一点: class Parent(models.Model): pass class Child(models.Model): parent = models.ForeignKey(Parent) parent = Parents.objects.get(id=1) for child in parent.child_set.all(): print id(child.parent

Django的ORM(版本1.2.3)在来回跟踪外键时不保留标识。最好用一个例子来说明这一点:

class Parent(models.Model):
    pass

class Child(models.Model):
    parent = models.ForeignKey(Parent)

parent = Parents.objects.get(id=1)
for child in parent.child_set.all():
    print id(child.parent), "=!", id(parent)
因此,对于每个子级,都会从数据库中重新获取父级,即使在获取子级时我们知道父级。这对我来说是违反直觉的

在我的例子中,这也会导致性能问题,因为我在父级执行一些繁重的操作,我希望在对象实例级缓存这些操作。但是,由于这些计算的结果是通过child=>parent链接访问的,因此在父级的缓存是无用的

有没有办法解决这个问题


我已经弄清楚了有一个ForeignRelatedObjectsDescriptor和一个ReversesingRelatedObjectDescriptor。

Django的ORM不遵循“反向”关系。这意味着每次访问
child.parent
时,它都会进行新的数据库调用

在某些(但不是所有)情况下解决此问题的一种方法是过滤
子对象
并在执行此操作时使用
选择相关()。这将减少数据库调用的数量,因为在查询执行时对子表和父表进行了连接,并且在访问
child.parent
时不会触发单独的查询

例如

from django.db import connection

parent = Parents.objects.get(id=1)
print parent
print len(connection.queries) # say, X

children = Child.objects.select_related().filter(parent = parent)
for child in children:
    print child.parent

print len(connection.queries) # should be X + 1

parent
child.parent
的Python对象id将不同,但您将看到在访问
child.parent
时不会触发其他查询

有许多可能的解决方案

也许最简单的方法是自己跟踪父母:

parent = Parents.objects.get(id=1)
for child in parent.child_set.all():
    child._parent_cache = parent
\u FOO\u cache
是Django跟踪通过ForeignKey获取的项目的方式,因此,如果您使用已有的父对象在子对象上预填充该对象,Django在引用
child.parent
时将不会再次获取该对象


或者,您可以查看尝试修复此问题的第三方库之一(我知道有两个)。

问题在于您仍然在向数据库添加不必要的工作—在本例中,是一个连接—虽然没有整个单独查询那么昂贵,但确实增加了一些权重。此外,OP说他已经对
父对象
做了一些昂贵的计算-这些不会继续。你是对的。特别是计算使得这不是一个有效的解决方案。正如Daniel所说:这并不能真正解决我的问题,因为“家长”中的计算非常昂贵。谢谢。在我注意到你的答复之前,我确实实施了“自己跟踪家长”选项。不过,其他两种解决方案似乎都很有希望,所以下次遇到这个问题时,我可能会研究它们。