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 во время итерации, то запросы могут быть связаны с этим.

Вернуться на верх