Django Prefetch Related Still Queries
У меня есть функция
def selected_location_equipment(self):
qs = (Equipment.objects
.prefetch_related('service_logs')
.all())
return qs
Это возвращает набор запросов с несколькими связанными полями, захваченными.
Проблема в том, что когда я обращаюсь к предварительно найденным данным позже в моем коде, он снова выполняет запрос.
Я просмотрел код Django и вижу, где он проверяет кэш на .all() в одном месте и не запрашивает, но затем, когда он вызывается здесь, кэш как будто очищается.
Панель инструментов отладки также показывает запрос для каждой итерации цикла.
for e in equipments:
last_service = list(e.service_logs.all())[-1]
for log in e.service_logs.all():
# do other stuff
...
Вот базовое определение модели для оборудования
class ServiceLog(models.Model):
equipment = models.ForeignKey(Equipment,
on_delete=models.CASCADE,
related_name='service_logs')
Если вы хотите получить только последний журнал обслуживания для каждого оборудования и избежать лишнего расхода памяти, вы также можете использовать annotate() или Prefetch с фильтрацией:
from django.db.models import Prefetch
# Prefetch only the latest service log
qs = Equipment.objects.prefetch_related(
Prefetch('service_logs', queryset=ServiceLog.objects.order_by('-id'), to_attr='prefetched_service_logs')
)
for e in qs:
last_service = e.prefetched_service_logs[0] if e.prefetched_service_logs else None
Вероятно, проблема в том, что вы используете .all()
в цикле, заставляя запрос запускаться снова. Если вы хотите избежать лишних запросов, то получайте данные только один раз:
for e in equipments:
service_logs = list(e.service_logs.all())
last_service = service_logs[-1]
for log in service_logs:
...
Хотя странно, что debug Toolbar показывает запрос для каждой итерации, потому что Django должен кэшировать результат согласно docs. Если вы выполняете действия с log
во время итерации, то запросы могут быть связаны с этим.