FileField 中的 'upload_to' 回调是否命中相关内容的数据库?

Does the 'upload_to' callback in the FileField hit the db for related content?

我有一个 Attachment 模型,带有两个 ForeignKey 字段和 upload_to 属性的 get_attachment_path 回调:

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 会两次访问数据库吗(一次针对 .create,另一次针对 get_attachment_path)?询问它是因为 get_attachment_path 回调试图访问相关数据(instance.chat.id 等)。

如果是这样,有什么办法可以优化吗?

不,它不会命中数据库,因为您已经将现有和保存的 (!) OwnerChat 对象传递给 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 查询。