Кэширование запросов Django через ForeignKey в GenericRelation

Используя GenericRelation на карту Recordс Persons, у меня есть следующий код, который работает правильно, но есть проблема производительности, которую я пытаюсь решить:

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с RecordXs, чтобы избежать n запросов, когда страница будет отображать n RecordX объекты?

Спасибо за вашу помощь!

1 ответ

Решение

Видимо, мне нужно было позвонить обоим - prefetch_related('people', 'people__person'), ВЗДОХ.

Другие вопросы по тегам