I am working a improving the amount of database hits my Django application makes, and one of my gripes is with the Django forms.
When I GET a page with a form, it will load objects from the database in order to fill in ModelChoiceField
s, which is great.
When I POST some form data, the form will clean the data. Now, in my clean_foo
method of the form, I want to access one of the foo
objects relations: foo.bar
. This will hit the database to get the bar
object.
Is there any way for me to prefetch bar
? What I mean is that when the form uses the pk
to find the foo
object, can I have it prefetch the bar
as well? Where might I do that?
Looking at the Django source code, it seems that the chosen object is fetched directly with .get()
and not as a queryset 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, what that tells me is that I am not supposed to try anything there. Best thing I can do is
def clean_foo(self):
foo = Foo.objects.filter(pk=self.cleaned_data['foo'].pk).select_related('bar')
[...]
There I can prefetch what I need for the rest of the logic. So it won't be 1 query, but I can make it at most 2 queries.
I realise this is starting to sound like a statement and not a question, so please just prove me wrong, if possible
It seems like you could use select_related
directly in the definition of the queryset for your field:
class MyForm(forms.ModelForm):
my_field = forms.ModelChoiceField(queryset=Foo.objects.select_related('bar'))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With