Модели Django: сохранение идентичности объекта по внешнему ключу после - PullRequest
2 голосов
/ 15 сентября 2010

ORM Django (версия 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 и ReverseSingleRelatedObjectDescriptor.

Ответы [ 2 ]

6 голосов
/ 15 сентября 2010

Существует несколько возможных решений этой проблемы.

Пожалуй, проще всего самостоятельно отследить родителя:

parent = Parents.objects.get(id=1)
for child in parent.child_set.all():
    child._parent_cache = parent

_FOO_cache - это способ, которым Django отслеживает элементы, извлеченные с помощью ForeignKey, поэтому, если вы предварительно заполните этот объект дочернего элемента уже имеющимся у вас родителем, Django не будет извлекать его снова, когда вы ссылаетесь на child.parent.

В качестве альтернативы, вы можете обратиться к одной из сторонних библиотек, которые пытаются это исправить - django-idmapper или django-selectreverse - это две из моих знакомых.

1 голос
/ 15 сентября 2010

ORM Джанго не следует "обратным" отношениям.Это означает, что каждый раз, когда вы обращаетесь к child.parent, он выполняет новый вызов базы данных.

Одним из способов решения этой проблемы в некоторых (но не во всех) ситуациях является фильтрация Child объектов и использование при этом select_related().Это сократит количество вызовов базы данных, так как дочерние и родительские таблицы объединяются во время выполнения запроса, и при обращении к 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
* 1011Идентификатор объекта Python parent и child.parent не будет одинаковым, но вы увидите, что при обращении к child.parent дополнительные запросы не запускаются.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...