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()
:仍然疯狂缓慢。 最佳答案
为什么会这样,我又该如何强制从多个领域进行预取?
发生这种情况的原因是因为您进行的查询与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
所引用的模型。关于python - 预取manytomany字段不会改变执行速度,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57844912/