【问题标题】:Prevent Django from querying for ForeignKey options for every form in ModelFormSet防止 Django 为 ModelFormSet 中的每个表单查询 ForeignKey 选项
【发布时间】:2013-02-18 15:19:24
【问题描述】:

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

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

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

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

【问题讨论】:

标签: django django-forms django-database


【解决方案1】:

Django 表单集只是将表单创建的所有细节委托给表单对象本身,并且各个表单实例不知道其他表单实例,因此每个实例都必须查询自己的选择也就不足为奇了。

缓存也可能产生意想不到的副作用——例如,表单的__init__ 函数可能依赖于它接收到的initial 数据,从而导致缓存的form 对象不正确。

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

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

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

您的表单集将需要重写一个方法来运行查询集并将它们传递到构造它们的表单中:

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))

(请参阅 the Django source 了解其工作原理)

【讨论】:

  • 感谢您抽出宝贵时间回答我的问题。你的解决方案是我的想法,但现在我知道这是要走的路!
  • 我用这个解决方案解决了同样的问题,但是保存时我得到“无法分配“u'7'”:“Stop.city”必须是“City”实例。” Stop 是具有 City fk 的 ModelForm(用于构建表单集)。有什么办法可以绕过它吗?,这样走得更远似乎开销很大。
  • @mariodev,我认为您可能需要发布更多代码来帮助解释/追踪问题。 cmets 中可能没有足够的空间来做到这一点,所以它可能更适合自己的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 2018-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多