Django prefetch on cleared data

I am working on improving the number of backups that fall into a Django application, and one of my problems is with Django forms.

When I get the page with the form, it will load objects from the database to fill in ModelChoiceFields, which is great.

When I send POST some form data, the form will clear the data. Now, in my method clean_fooform, I want to get access to one of the relations of objects foo: foo.bar. This will delete the database to get the object bar.

Is there a way to prefetch bar? I mean, when a form uses pkto search for an object foo, can I prefetch it bar? Where can i do this?

Looking at the source code of Django , it seems that the selected object is selected directly using .get(), rather than as a collection of queries with.filter()

def to_python(self, value):
    if value in self.empty_values:
        return None
    try:
        key = self.to_field_name or 'pk'
        value = self.queryset.get(**{key: value})    # <-- Right here
    except (ValueError, TypeError, self.queryset.model.DoesNotExist):
        raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
    return value

So this is what tells me that I should not try anything there. The best I can do is

def clean_foo(self):
    foo = Foo.objects.filter(pk=self.cleaned_data['foo'].pk).select_related('bar')
    [...]

There I can pre-select what I need for the rest of the logic. Thus, it will not be 1 request, but I can make no more than two requests.

I understand that this is starting to sound like an expression, not a question, so please just prove that I'm wrong, if possible

+4
2

, select_related :

class MyForm(forms.ModelForm):
    my_field = forms.ModelChoiceField(queryset=Foo.objects.select_related('bar'))
+5

: , , , .

ModelChoiceField to_python , select_related.

, .

class MyModelChoiceField(forms.ModelChoiceField):
    def __init__(self, *args, select_related=(), prefetch_related=(), **kwargs):
        super(MyModelChoiceField, self).__init__(*args, **kwargs):
        self._selects = select_related
        self._prefetches = prefetch_related

    def to_python(self, value):
        if value in self.empty_values:
            return None
        try:
            key = self.to_field_name or 'pk'
            values = self.queryset.filter(
                **{key: value}
            ).select_related(
                *self._selects
            ).prefetch_related(
                *self._prefetches
            )
            value = values.first()
        except (ValueError, TypeError, self.queryset.model.DoesNotExist):
            raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice')
        return value
+2

Source: https://habr.com/ru/post/1620727/


All Articles