Creating Empty Querysets by Default

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 set queryset 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.