Кэширование запросов Django через ForeignKey в GenericRelation
Используя GenericRelation
на карту Record
с Person
s, у меня есть следующий код, который работает правильно, но есть проблема производительности, которую я пытаюсь решить:
models.py
class RecordX(Record): # Child class
....
class Record(models.Model): # Parent class
people = GenericRelation(PersonRecordMapping)
def people_all(self):
# Use select_related here to minimize the # of queries later
return self.people.select_related('person').all()
class Meta:
abstract = True
class PersonRecordMapping(models.Model):
person = models.ForeignKey(Person)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Person(models.Model):
...
В итоге я имею:
RecordX ===GenericRelation===> PersonRecordMapping ===ForeignKey===> Person
Логика отображения в моем приложении следует этим отношениям, чтобы отобразить все Person
привязаны к каждому RecordX
:
views.py
@rendered_with('template.html')
def show_all_recordXs(request):
recordXs = RecordX.objects.all()
return { 'recordXs': recordXs }
Проблема приходит в шаблоне:
template.html
{% for recordX in recordXs %}
{# Display RecordX's other fields here #}
<ul>
{% for map in record.people_all %}{# <=== This generates a query every time! #}
<li>{{ map.person.name }}</li>
{% endfor %}
</ul>
{% endfor %}
Как указано, каждый раз, когда я запрашиваю Person
связано с RecordX
, он генерирует новый запрос. Кажется, я не могу понять, как выполнить предварительную выборку, чтобы избежать лишних запросов.
Если я попробую selected_related
Я получаю ошибку, что нет selected_related
поля возможны здесь (сообщение об ошибке: Invalid field name(s) given in select_related: 'xxx'. Choices are: (none)
). Не удивительно, теперь я вижу - на этой модели нет никаких ФК.
Если я попробую prefetch_related('people')
, не выдается никакой ошибки, но я по-прежнему получаю те же повторные запросы в каждом цикле в шаблоне, как и раньше. Аналогично для prefetch_related('people__person')
, Если я попробую prefetch_related('personrecordmapping')
Я получаю ошибку.
В соответствии с этим ответом я подумал о том, чтобы попытаться смоделировать select_related
через что-то вроде:
PersonRecordMapping.objects.filter(object_id__in=RecordX.objects.values_list('id', flat=True))
но я не понимаю _content_object_cache
достаточно хорошо, чтобы адаптировать этот ответ к моей ситуации (если даже правильный подход).
Итак, как я могу предварительно получить все Person
с RecordX
s, чтобы избежать n запросов, когда страница будет отображать n RecordX
объекты?
Спасибо за вашу помощь!
1 ответ
Видимо, мне нужно было позвонить обоим - prefetch_related('people', 'people__person')
, ВЗДОХ.