首页 > 解决方案 > Django ModelFormSet 在验证时对每个 formset 实例执行一个单对象 SELECT 查询(ORM 效率低下)

问题描述

问题的概念总结:

以下是我尝试过的几件事:

在我看来,最简单的解决方案BaseModelFormSet._object_dict是以某种方式传递给创建的每个 ModelForm,然后允许在进行另一个 SELECT 查询之前ModelChoiceField检查它。_object_dict

附录:

这是来自 Django-Debug-Toolbar 的屏幕截图,显示了第一个 SELECT 查询(这是传递给 BaseModelFormSet 的查询集),然后是 4 个单独的 SELECT 查询(每个 form.instance 一个) 在此处输入图像描述

注意:我也在此处将其作为 Django 票发布: https ://code.djangoproject.com/ticket/32244#comment:1

即使这可以通过某种形式的缓存来解决,它仍然看起来仍然是低效的应用层逻辑。

标签: djangoormdjango-formsformset

解决方案


我想出了一个非常老套的解决方法,它保留了我们需要的表单集功能。基本上BookForm你可以覆盖ModelForm._clean_fields()

def _clean_fields(self):
        # remove 'id' field so it's not cleaned 
        # (this is the ModelChoiceField that's generating an extra SELECT query per Book object in the formset during clean)
        id_field = self.fields.pop('id')

        # run normal cleaning, with the form now unaware of its own 'id' field
        super(BookForm, self)._clean_fields()

        # add 'id' field back and insert it into clean_data
        id_value = id_field.widget.value_from_datadict(self.data, self.files, self.add_prefix('id'))
        self.cleaned_data['id'] = id_value

        # add the 'id' field back into the form
        self.fields['id'] = id_field

推荐阅读