python - Django formset,查询每个表单的关系字段

标签 python django django-models django-forms django-queryset

模型.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 表单集

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 个查询。

  • 1 个用于 PurOrder 实例,
  • 1 个用于 PurOrderItem 实例
  • 20 个 PurOrderItem 的选定 Material 。

想想看,如果有1000个PurOrderItem

使用提供的 select_related,它将 Material 添加到 PurOrderItemselect,但我认为在显示它时,它会再次查询。

我使用 django-autocomplete-light,所以它使我免于查询所有 Material 实例,但它会不断查询选定的 Material ,即使我选择了相关 Material 也会显示它。

理想情况下,我会选择带有预取 purorderitem 和相关 Material 的 PurOrder 实例,这意味着 3 个查询。轮到他们时,将使用预取的 purorderitem 和 Material 。

请告诉我一种避免选择查询的方法。

注意:我尽量避免在这里缓存。

更新

在我创建这个问题很久之后,我尝试了提供的解决方案。 问题是,formset 的表单彼此不了解。因此,前提是查询集的 selected_related 或 prefetch_related 查找未传递到表单集表单。

最佳答案

你很好。此代码仅花费您 3 次查询。 正如您在 select_related() 中看到的那样文档:

Returns a QuerySet that will “follow” foreign-key relationships, selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won’t require database queries.

这意味着您的代码将执行 mysql join 并将生成包含所有数据的数据集。因此,我可以看出您的代码非常好。

我建议您使用某种分析,例如 django-silk查看生成了多少查询。

脚注:

正如您在 prefetch_related() 中看到的那样文档中,prefetch_related()select_related() 之间的区别在于它们执行连接的方式:

This (prefetch_related) has a similar purpose to select_related, in that both are designed to stop the deluge of database queries that is caused by accessing related objects, but the strategy is quite different.

...

select_related works by creating an SQL join and including the fields of the related object in the SELECT statement. For this reason, select_related gets the related objects in the same database query.

...

prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python.

所以只要你需要一对一关系,select_related是查询关系最高效的方式。

关于python - Django formset,查询每个表单的关系字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48767853/

相关文章:

python - struct.unpack 不返回字符串

python - 无法在基于 asyncio 构建的脚本中使用 https 代理以及重用同一 session

Python Lambda 实践

mysql - Django-查询过滤器,具有外部关系

django - 仅在调用更新时发布保存信号

python - 将 pandas 数据框列中的单词按另一列分组以获得频率/计数

django - Heroku Django DEBUG 设置未应用

mysql - django 模型中的大型 json 数据会减慢任何查询速度

mysql - Django - MySQL 数据库日期时间字段被清除

python - 增加数据库中的 IntegerField 计数器