Оптимизация 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.

Заранее благодарю за помощь.

Вернуться на верх