Paul's Programming Notes     Archive     Feed     Github

Django - ModelChoiceField queryset caching

It would be nice to know a better way to cache the ModelChoiceField’s queryset when it’s used in a form that runs “is_valid()” in a loop (like Formsets do). The best way I know how at the moment is by not using a ModelChoiceField at all. The solution requires using a ChoiceField, running the query for choices outside of the loop, then passing the choices into the form to override the ChoiceField choices.

Here’s an example:

# See full example: https://github.com/pawl/django_modelchoicefield_caching/blob/master/myapp/views.py#L31-L51
for song in playlist:
form_data = {'title': song["title"], 'artist': song["artist"]}
song_form = forms.SongFormWithModelChoiceField(data=form_data)
song_form.is_valid() # runs a query to get the ModelChoiceField queryset each time
print('ModelChoiceField - query count AFTER validating all songs:',
len(connection.queries)) # 5 queries
# query for choices outside of the loop to prevent unnecessary queries
artist_choices = [(artist.pk, artist.name)
for artist in models.Artist.objects.all()]
for song in playlist:
form_data = {'title': song["title"], 'artist': song["artist"]}
# pass choices into the Form
song_form = forms.SongFormWithChoiceField(
artist_choices=artist_choices,
data=form_data)
song_form.is_valid()
print('ChoiceField w/ choices passed in - query count AFTER validating all songs:',
len(connection.queries)) # 6 queries (only 1 more query!)
view raw example.py hosted with ❤ by GitHub