防止 Django 为 ModelFormSet 中的每个表单查询外键选项 [英] Prevent Django from querying for ForeignKey options for every form in 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屋!