django-autocomplete-light tutorial

Overview

Autocompletes are based on 3 moving parts:

  • widget, does the initial rendering,
  • javascript widget initialization code, to trigger the autocomplete,
  • and a view used by the widget script to get results from.

Create an autocomplete view

The only purpose of the autocomplete view is to serve relevant suggestions for the widget to propose to the user. DAL leverages Django’s class based views and Mixins to for code reuse.

Note

Do not miss the Classy Class-Based Views website which helps a lot to work with class-based views in general.

In this tutorial, we’ll learn to make autocompletes backed by a QuerySet. Suppose we have a Country Model which we want to provide a Select2 autocomplete widget for in a form. If a users types an “f” it would propose “Fiji”, “Finland” and “France”, to authenticated users only. The base view for this is Select2QuerySetView.

from dal import autocomplete

from your_countries_app.models import Country


class CountryAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated():
            return Country.objects.none()

        qs = Country.objects.all()

        if self.q:
            qs = qs.filter(name__istartswith=self.q)

        return qs

Note

For more complex filtering, refer to official documentation for the QuerySet API.

Register the autocomplete view

Create a named url for the view, ie:

from your_countries_app.views import CountryAutocomplete

urlpatterns = [
    url(
        'country-autocomplete/$',
        CountryAutocomplete.as_view(),
        name='country-autocomplete',
    ),
]

Danger

As you might have noticed, we have just exposed data through a public URL. Please don’t forget to do proper permission checks in get_queryset.

Use the view in a Form widget

We can now use the autocomplete view our Person form, for its birth_country field that’s a ForeignKey. So, we’re going to override the default ModelForm fields, to use a widget to select a Model with Select2, in our case by passing the name of the url we have just registered to ModelSelect2:

from dal import autocomplete

from django import forms


class PersonForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = ('__all__')
        widgets = {
            'birth_country': autocomplete.ModelSelect2(url='country-autocomplete')
        }

If we need the country autocomplete view for a widget used for a ManyToMany relation instead of a ForeignKey, with a model like that:

class Person(models.Model):
    visited_countries = models.ManyToMany('your_countries_app.country')

Then we would use the ModelSelect2Multiple widget, ie.:

widgets = {
    'visited_countries': autocomplete.ModelSelect2Multiple(url='country-autocomplete')
}

Using autocompletes in the admin

We can make ModelAdmin to use our form, ie:

from django.contrib import admin

from your_person_app.models import Person
from your_person_app.forms import PersonForm


class PersonAdmin(admin.ModelAdmin):
    form = PersonForm
admin.site.register(Person, PersonAdmin)

Note that this also works with inlines, ie:

class PersonInline(admin.TabularInline):
    model = Person
    form = PersonForm