【问题标题】:Optimize validation for a ModelChoiceField inside a formset Django?优化表单集 Django 中 ModelChoiceField 的验证?
【发布时间】:2015-09-23 08:52:04
【问题描述】:

当您提交数据时,Django 的内联表单集所做的第一件事就是在循环中对其每个表单进行触发验证:

for i in range(0, self.total_form_count()):
     form = self.forms[i]
     self._errors.append(form.errors)

在表单集是包含各个表单行的表格的图片中,验证是逐行进行的。如果表单中有ModelChoiceField,则每行中选择的值将在ModelChoiceField的查询集中查找,导致每行至少有一个额外的db命中。

key = self.to_field_name or 'pk'
value = self.queryset.get(**{key: value})

现在,如果所有这些查询集都相同(和我的一样),这似乎是一种浪费。查询集不会逐行变化,有什么办法缓存吗?

更一般地说,在列中进行验证是否会更有效,例如,首先从表单的类中收集字段,然后对每个字段(列)的所有表单(行)进行循环?

【问题讨论】:

    标签: django validation formset


    【解决方案1】:

    您可以通过将ModelChoiceField 替换为正常的ChoiceField 来避免查询集,该ChoiceField 由代码中前面填充的选项提供,例如:

    class YourModelForm(forms.ModelForm)
        your_foreign_field = forms.ChoiceField(choices=list(YourForeignModel.objects.values_list('id', 'display_name')))
    

    这样,查询集将在创建类(不是类对象)时执行一次。但这会导致一些麻烦 - 应用程序启动时(或第一次到达此代码时)将填充外来对象列表。为避免这种情况,您可以将您的选择移至__init__

    class YourModelForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            choices = kwargs.pop('your_foreign_choices')
            super(YourModelForm, self).__init__(*args, **kwargs)
            self.fields['your_foreign_field'] = forms.ChoiceField(choices=choices)
    

    这样,您需要做的就是将填充的选项传递给您的表单集(因此它将被进一步传递到每个表单中):

    YourModelFormSet = modelformset_factory(YourModelForm)
    
    def your_view(request):
        formset =  YourModelFormSet(form_kwargs={'your_foreign_choices': list(YourForeignModel.objects.values_list('id', 'display_name'))})
    

    【讨论】:

    • 但是你失去了所有模型的优点,比如开箱即用的验证、保存等......
    • 保存已正确完成,验证也是 - 除非您的选择生成错误,但您也可以在这里使用ModelChoiceField,它应该可以正常工作。将ModelChoiceField 与选项一起使用将阻止查询集的执行,字段将使用预先填充的选项。
    • 作为参考,在 Django > 2 中,您不能将选择传递给 ModelChoiceField
    猜你喜欢
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 2011-01-07
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多