在伪代码中,我有一个这样的数据库模型:
Model T
name
tags = models.ManyToManyField(Tag, related_name="Ts")
symbol = models.ForeignKey(Symbol)
Model Symbol
name
category = models.ForeignKey(Category)
Model Tag
name
这是我用来导出它的代码:
query = T.objects.annotate(category_id=F('symbol__category_id')).prefetch_related('tags')
for t in query:
_dict = model_to_dict(t)
_dict["category_id"] = t.category_id
_tags = []
for tag in _dict["tags"]
_tags.append(tag.id)
_dict["tags"] = _tags
在这段代码中,_dict
给了我想要的结果。
但是,T还有许多我不需要的其他字段,因此我将query
更改为:
T.objects.only("name", "symbol", "tags").annotate(category=F('symbol__category_id')).prefetch_related('tags')
由于某种原因,这会降低执行速度。
原始查询需要6秒,而最后一个查询需要8秒。为什么?
如何正确地预取所有内容,从而不必遍历标签并将其ID附加到字典中?如何同时使用.only()
来做到这一点?
编辑:
由于某些原因,使用.defer()
而不是仅使用它,并指出我不需要的字段,可以在不影响性能的情况下起作用。
defer
和only
有什么区别,为什么会造成性能瓶颈?
答案 0 :(得分:1)
使用fields = ("name", ...)
from django.db.models import Prefetch
prefetch = Prefetch('tags', queryset=Tag.objects.only('id'))
query = T.objects.prefetch_related(prefetch).annotate(category_id=F('symbol__category_id')).only(*fields)
for t in query:
_dict = model_to_dict(t, fields=[*fields, tags])
_dict["category_id"] = t.category_id
_dict["tags"] = [tag.id for tag in _dict["tags"]]