Django forms are a powerful way to generate forms and validate input in Django applications. By default, Django form fields like ChoiceField and ModelChoiceField will query the database to populate the field choices. However, in some cases you may want to avoid hitting the database on form initialization and instead start with an empty queryset. In this blog post, we’ll explore a few methods for creating empty querysets by default in Django form fields.
Why Empty Querysets?
There are a few reasons why you may want to use an empty queryset as the initial value for a form field:
- Avoid unnecessary database queries – Populating choices requires hitting the backend database. For performance reasons, you may want to avoid this on forms that rarely need populated choices.
- Defer population until needed – The choices may not be needed if form validation fails, so you can defer the population until later in the request cycle.
- Data not yet available – The data for the choices may not be available yet when the form is initialized. Using an empty queryset allows creating the form before the data can be loaded.
- Simpler testing – Tests can stub model methods more easily if the form does not actively load data on initialization.
So in summary, an empty queryset can help optimize performance, simplify logic, and enable more modular and testable code.
Django Default Behavior
By default Django form fields like ChoiceField
and ModelChoiceField
will run a database query on initialization to populate choices:
class MyForm(forms.Form):
category = forms.ModelChoiceField(Category.objects.all())
This immediately queries the Category
model to retrieve all objects, before the form is displayed or submitted.
If the category list is large or expensive to load, we likely want to avoid this frontend load query. So how can we start with an empty queryset instead?
Method 1: Specify Empty Querysets
The easiest way to initialize a form field with an empty queryset is by simply passing an empty queryset:
from django.db.models import QuerySet
class MyForm(forms.Form):
category = forms.ModelChoiceField(
queryset=Category.objects.none())
We import QuerySet
and use the .none()
method to return an empty queryset. Any form field that accepts a queryset
parameter can initialize with an empty query this way.
Method 2: Override init
Another approach is to override the field’s __init__
method and set the queryset
attribute directly:
class MyForm(forms.Form):
category = forms.ModelChoiceField(Category.objects.all())
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category'].queryset = Category.objects.none()
This will again start the field with an empty queryset before the form is displayed.
Method 3: Use View/Form Logic
Instead of defining the empty queryset at the form field level, we can implement the logic in the view handler instead:
def my_view(request):
form = MyForm(initial={'category': Category.objects.none()})
# Populate queryset later as needed
if request.method == 'POST':
form.fields['category'].queryset = Category.objects.all()
return render(request, 'form.html', {'form': form})
Here we initialize the form with an empty queryset, and populate it only if validation succeeds on form submit.
When to Populate the Querysets
Some options for when to populate the queryset include:
- In the view on form submission
- In the form’s
clean()
method - Using an asynchronous endpoint to load choices after page load
Summary
There are a few ways to create empty querysets by default in Django forms:
- Pass an empty QuerySet to the field on initialization
- Override
__init__
and setqueryset
to an empty QuerySet - Manage the queryset population at the view or form level
Using an initial empty queryset can optimize performance, simplify testing, and allow more modular form code.
By understanding these techniques, you can avoid unnecessary database queries and provide a smoother experience by only loading form choices when they are needed. empty querysets give you more control over when and how form fields hit the database.