Обратный вызов 'upload_to' в поле FileField обращается к базе данных за связанным содержимым?

У меня есть Attachment модель с двумя полями ForeignKey и get_attachment_path обратным вызовом для upload_to атрибута:

def get_attachment_path(instance, filename):
    return f'{instance.owner.name}/{instance.chat.id}/{filename}'

class Attachment(models.Model):
    owner = models.ForeignKey(..)
    chat = models.ForeignKey(..)
    file = models.FileField(upload_to=get_attachment_path, ...)

Нижеприведенная строка вызовет выполнение get_attachment_path:

Attachment.objects.create(..., file=file)

Итак, при использовании приведенной выше строки, будет ли django обращаться к db дважды (один раз для .create и другой раз для get_attachment_path)? Спрашиваю это потому, что обратный вызов get_attachment_path пытается получить доступ к связанным данным (instance.chat.id и т.д.).

Если да, то есть ли способ оптимизировать его?

Нет, он не попадет в БД, потому что вы уже передаете существующие и сохраненные(!) Owner и Chat объекты в Attachment.objects.create, поэтому обработчику загрузки не нужно извлекать их из базы данных.

Однако при получении вложения из базы данных будут сделаны дополнительные запросы на связанные объекты:

attachment = Attachment.objects.get(id=some_id)
attachment.file.save(...)

В этом случае использование select_related может убрать лишние запросы.

Вы всегда можете проверить выполняемые SQL-запросы (только в режиме DEBUG):

from django.db import connection

def get_attachment_path(instance, filename):
    print('Queries before', connection.queries)
    path = f'{instance.owner.name}/{instance.chat.id}/{filename}'
    print('Queries after', connection.queries)
    return path

В качестве альтернативы, Django Debug Toolbar является отличным дополнением к проекту Django для оптимизации SQL запросов.

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