m = MyModel.objects.all().only("colA", "colB").prefetch_related("manyToManyField")
for mm in m:
print(mm.id)
list(mm.manyToManyField.values_list('id', flat=True))
此代码执行时间太长。
这几乎不需要时间(循环中没有对manyToManyField的引用):
m = MyModel.objects.all().only("colA", "colB").prefetch_related("manyToManyField")
for mm in m:
print(mm.id)
这几乎与第一个完全一样
m = MyModel.objects.all().only("colA", "colB")
for mm in m:
print(mm.id)
list(mm.manyToManyField.values_list('id', flat=True))
这使我认为.prefetch_related("manyToManyField")
毫无用处,实际上并没有获取任何东西,list(mm.manyToManyField.values_list('id', flat=True))
在每个周期都访问数据库。
这是为什么,我怎么能强制从多方字段中预取?
我尝试删除list()
,但是mm.manyToManyField.all().values_list
给了我一个不是JSON可序列化的查询集(不,我不想安装rest框架)。
还尝试了list(mm.manyToManyField.all().values_list)
和list()
:仍然疯狂得很慢。
答案 0 :(得分:2)
这是为什么,我怎么能强制从多方字段中预取?
发生这种情况的原因是因为您进行的查询与manyToManyField.all()
不同,因此没有执行 。假设您会myManyToManyField.filter(some_col=some_val)
,那么它也会对数据库产生影响,因为已对数据库进行了优化以有效过滤。
如果要获取值,请使用:
# no extra query
for mm in m:
print(list(mm.manyToManyField.all()))
或者如果您想打印主键,则可以通过列表理解来获取它们,例如:
# no extra query
for mm in m:
print([k.id for k in mm.manyToManyField.all()])
它不会进行其他查询,因为您已经用.prefetch_related('manyToManyField')
加载了该查询,但是未加载所有变体,例如过滤,注释等。
不过,您可以传递任意查询集以使用Prefetch
objects [Django-doc]进行预取。例如,如果您要检索.values_list('id')
,则可以使用以下方法进行预取:
from django.db.models import Prefetch
m = MyModel.objects.only("colA", "colB").prefetch_related(
Prefetch(
'myManyToManyField',
queryset=TargetModel.objects.filter(pk__gt=5),
to_attr='filtered_pks'
)
)
然后,由此产生的MyModel
将在此处具有一个额外的属性'filtered_pks'
,其中包含该相关模型的.filter(pk__gt=5)
。因此,TargetModel
是ManyToManyField
所引用的模型。