防止 Django 为 ModelFormSet 中的每个表单查询外键选项 [英] Prevent Django from querying for ForeignKey options for every form in ModelFormSet

查看:18
本文介绍了防止 Django 为 ModelFormSet 中的每个表单查询外键选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的 Django 应用程序构建一个 csv 导入表单,并希望在 ModelFormSet 中显示要导入的行以进行验证.

I'm building a csv import form for my Django application and want to display the to-be-imported rows in a ModelFormSet for validational purposes.

因此,我向相关的 ModelAdmin 添加了一个视图,它从 csv 中读取行并打印一个 ModelFormSet(queryset=an_empty_queryset, initial={data_from_the_csv}).

Therefore I added a view to the relevant ModelAdmin which reads the lines from the csv and prints a ModelFormSet(queryset=an_empty_queryset, initial={data_from_the_csv}).

问题是模型通过 ForeignKey 字段引用了其他三个模型,并且对于表单集中的每个表单中的每个字段,发出数据库查询以填充ModelChoiceField 的选项.

The problem is that the model references three other models via ForeignKey fields and for each field in each form in the formset a database query is issued in order to populate the ModelChoiceField's options.

为什么 Django 不缓存表单(因为它被多次使用)或者已经有一种我不知道的方法来完成这个?

Why doesn't Django cache the form (as it is used several times) or is there already a way to accomplish this I don't know about yet?

推荐答案

Django 表单集只是将表单创建的所有细节委托给表单对象本身,单个表单实例不知道其他的,所以它不是'没想到每个人都必须查询自己的选择.

Django formsets just delegate all the details of form creation to the form objects themselves, and the individual form instances aren't aware of the others, so it isn't unexpected that each will have to query for its own choices.

缓存也可能有意想不到的副作用——例如,表单的 __init__ 函数可能依赖于它收到的 initial 数据,使得缓存的 表单 对象不正确.

Caching could also have unintended side effects--for example, the form's __init__ function could be dependent on the initial data it received, making the cached form object incorrect.

减少查询数量的最佳方法是检索选择查询集一次,然后将它们传递给构造函数中的表单类.这将需要定义一个自定义的 ModelForm 和一个自定义的 ModelFormSet.

The best way to reduce the number of queries would be to retrieve the choice querysets once and then pass them to your form classes in their constructor. This will require defining a custom ModelForm and a custom ModelFormSet.

您的表单将需要一个直接接受选择的构造函数:

Your form will need a constructor that accepts the choices directly:

from django.forms.models import ModelForm

class MyForm(ModelForm):
    def __init__(self, my_field_choices=None, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['my_field'].choices = my_field_choices

并且您的表单集将需要覆盖一个方法来运行查询集并将它们传递到构建的表单中:

And your formset will need to override a method to run the querysets and pass them into the forms as they're constructed:

from django.forms.models import BaseModelFormSet

class MyFormSet(BaseModelFormSet):
    def _construct_forms(self):
        # instantiate all the forms and put them in self.forms
        self.forms = []

        # Define each of your choices querysets
        my_field_choices = Model.object.filter(...)

        #Add your querysets to a dict to pass to the form
        form_defaults = {'my_field_choices': my_field_choices, }

        for i in xrange(min(self.total_form_count(), self.absolute_max)):
            self.forms.append(self._construct_form(i, **form_defaults))

(请参阅Django 源代码 以查看这将如何工作)

(see the Django source to look into how this would work)

这篇关于防止 Django 为 ModelFormSet 中的每个表单查询外键选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆