Оптимизация ModelChoiceField - слишком много запросов к formset.is_valid (сообщение)
У меня проблема с производительностью запроса с набором форм, включающим форму для модели с FK.
Я написал код в соответствии со стратегией 2, показанной в DjangoCon 2020 | Choose, and choose quickly: Optimising ModelChoiceField - Carlton Gibson. Это работает для get, но не для post.
В POST, даже если ничего не изменилось, во время formset.is_valid (или formset.save(commit = False)) у меня есть запросы для каждого FK в каждой форме. В общем, сотни запросов об одном и том же (в примере ниже для SampleModel). Как использовать инициализированные варианты для formset.save(commit=False)?
У меня есть:
class MyClass(models.Model):
name = models.CharField(max_length=100)
sample_model = models.ForeignKey('SampleModel', on_delete=models.PROTECT)
...
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
sample_model_choices = kwargs.pop("sample_model_choices", None)
...
super().__init__(*args, **kwargs)
if sample_model_choices:
self.fields["sample_model"].choices = sample_model_choices
...
class Meta:
model = MyClass
fields = ['name', 'sample_model', ...]
class MyFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sample_model_choices = [*forms.ModelChoiceField(SampleModel.objects.all()).choices]
...
def get_form_kwargs(self, index):
kwargs = super().get_form_kwargs(index)
kwargs['sample_model_choices'] = self.sample_model_choices
...
return kwargs
class Meta:
model = MyClass
И на заметку к посту:
if request.method == "POST":
myformset = modelformset_factory(MyClass, formset=MyFormSet, form=MyForm, extra=0, ...)
qs = MyClass.objects.filter(...
# i also tried prefetching data into qs but it doesn't help
formset = myformset(request.POST or None, queryset=qs)
if formset.is_valid(): # <- too many queries start here
Единственное, что, как мне кажется, работает, это брать данные непосредственно из formset.data, без clean_data, но я полагаю, что этого делать не следует. Должен ли я перезаписывать is_valid() или clean() на форме или на formset? Или есть какой-то способ заставить formset_save() использовать инициализированные варианты вместо запроса каждого поля с FK в каждой форме?
Для 100 форм в наборе форм я хотел бы иметь один запрос для каждого поля с FK, а не 100.
Заранее благодарю за помощь.