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
等)。
如果是这样,有什么办法可以优化吗?
不,它不会命中数据库,因为您已经将现有和保存的 (!) 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 查询。
我有一个 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
等)。
如果是这样,有什么办法可以优化吗?
不,它不会命中数据库,因为您已经将现有和保存的 (!) 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 查询。