首页 > 解决方案 > FileField 中的“upload_to”回调是否命中数据库以获取相关内容?

问题描述

我有一个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 会两次访问数据库(一次用于 the .create,另一次用于get_attachment_path)?询问它是因为get_attachment_path回调尝试访问相关数据(instance.chat.id等)。

如果是这样,有没有办法优化它?

标签: djangodatabasedjango-orm

解决方案


不,它不会命中数据库,因为您已经将现有和保存的(!)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 调试工具栏是 Django 项目的一个很好的补充,可以优化 SQL 查询。


推荐阅读