Models.py
class Material(BaseModelClass):
material = models.CharField(max_length=25, verbose_name='Material')
def __str__(self):
return self.material
class PurOrder(BaseModelClass):
order_number = models.CharField(max_length=25)
class PurOrderItem(BaseModelClass):
order = models.ForeignKey(PurOrder, on_delete=models.CASCADE)
material = models.ForeignKey(Material, on_delete=models.PROTECT)
我创建了一个PurOrder表单和PurOrderItem formset
PurOrderForm = modelform_factory(PurOrder, fields=('order_number',))
PurOrderFormset = inlineformset_factory(PurOrder, PurOrderItem,fields=('material',))
按如下方式初始化。
form = PurOrderForm(instance=order_instance)
queryset = order_instance.purorderitem_set.all().select_related('material',)
formset = PurOrderFormset(instance=order_instance, queryset=queryset)
如果选择的吩咐有20个PurOrderItem,则此设置会花费22个查询。
想一想,如果有1000个PurOrderItem
使用提供的select_related,它会向PurOrderItemselect添加材料,但是当我想它显示它时,它会再次查询。
我使用django-autocomplete-light,因此它可以避免查询所有材质实例,但它会不断查询所选材质,即使我选择了相关材质也能显示它。
理想情况下,我会选择具有预取purorderitem和相关材料的PurOrder实例,这意味着3个查询。当轮到他们时,将使用预取的purorderitem和材料。
请建议我避免选择查询的方法。
注意:我尽量避免在这里缓存。
更新
在我创建此问题后很长一段时间,我尝试了提供的解决方案。 问题是,formset的形式彼此不了解。因此,提供的查询集的selected_related或prefetch_related查找不会传递给表单集表单。
答案 0 :(得分:5)
返回一个QuerySet,它将“跟随”外键关系,在执行查询时选择其他相关对象数据。这是一个性能提升器,它会导致单个更复杂的查询,但意味着以后使用外键关系不需要数据库查询。
这意味着您的代码将预先形成mysql join
,并将生成包含所有数据的数据集。所以,我可以看到你的代码非常好。
我建议您使用django-silk之类的某种分析来查看正在生成的查询数。
脚注:
正如您在prefetch_related()文档中所看到的,prefetch_related()
和select_related()
之间的区别在于它们预先形成联接的方式:
这个( prefetch_related )与 select_related 的目的相似,因为两者都旨在阻止因访问相关对象而导致的数据库查询泛滥,但是战略是完全不同的。
...
select_related 的工作原理是创建SQL连接并包含字段 SELECT语句中的相关对象。为此原因, select_related 获取相同数据库查询中的相关对象。
...
另一方面,prefetch_related 对每个关系进行单独查找,并在Python中进行“加入”。
因此,只要您需要one-to-one
关系,select_related
就是查询关系的最有效方式。
答案 1 :(得分:0)
我最近意识到,在类似情况下,问题不在于表单集,而是模板中的{{formset.errors}},因为每个表单集都为此生成了一个查询。