Autocomplete classes

Note

This chapter assumes that you have been through the entire Quick start: adding simple autocompletes.

Design documentation

Any class which implements AutocompleteInterface is guaranteed to work because it provides the methods that are expected by the view which serves autocomplete contents from ajax, and the methods that are expected by the form field for validation and by the form widget for rendering.

However, implementing those methods directly would result in duplicate code, hence AutocompleteBase. It contains all necessary rendering logic but lacks any business-logic, which means that it is not connected to any data.

If you wanted to make an Autocomplete class that implements business-logic based on a python list, you would end up with AutocompleteList.

As you need both business-logic and rendering logic for an Autocomplete class to be completely usable, you would mix both AutocompleteBase and AutocompleteList resulting in AutocompleteListBase:

If you wanted to re-use your python list business logic with a template based rendering logic, you would mix AutocompleteList and AutocompleteTemplate, resulting in AutocompleteListTemplate:

So far, you should understand that rendering and business logic are not coupled in autocomplete classes: you can make your own business logic (ie. using redis, haystack ...) and re-use an existing rendering logic (ie. AutocompleteBase or AutocompleteTemplate) and vice-versa.

For an exhaustive list of Autocomplete classes, refer to the Autocomplete API doc.

One last thing: Autocomplete classes should be registered so that the view can serve them and that form fields and widget be able to re-use them. The registry itself is rather simple and filled with good intentions, refer to Registry API documentation.

Examples

Create a basic list-backed autocomplete class

Class attributes are thread safe because register() always creates a class copy. Hence, registering a custom Autocomplete class for your model in your_app/autocomplete_light_registry.py could look like this:

import autocomplete_light.shortcuts as al

class OsAutocomplete(al.AutocompleteListBase):
    choices = ['Linux', 'BSD', 'Minix']

al.register(OsAutocomplete)

First, we imported autocomplete_light‘s module. It should contain everything you need.

Then, we subclassed autocomplete_light.AutocompleteListBase, setting a list of OSes in the choices attribute.

Finally, we registered the Autocomplete class. It will be registered with the class name by default.

Note

Another way of achieving the above using the register shortcut could be:

autocomplete_light.register(autocomplete_light.AutocompleteListBase,
    name='OsAutocomplete', choices=['Linux', 'BSD', 'Minix'])

Using a template to render the autocomplete

You could use AutocompleteListTemplate instead of AutocompleteListBase:

import autocomplete_light.shortcuts as al

class OsAutocomplete(al.AutocompleteListTemplate):
    choices = ['Linux', 'BSD', 'Minix']
    autocomplete_template = 'your_autocomplete_box.html'

al.register(OsAutocomplete)

Inheriting from AutocompleteListTemplate instead of AutocompleteListBase like as show in the previous example enables two optionnal options:

See Design documentation for details.

Note

Another way of achieving the above could be:

autocomplete_light.register(autocomplete_light.AutocompleteListTemplate,
    name='OsAutocomplete', choices=['Linux', 'BSD', 'Minix'],
    autocomplete_template='your_autocomplete_box.html')

Creating a basic model autocomplete class

Registering a custom Autocomplete class for your model in your_app/autocomplete_light_registry.py can look like this:

from models import Person

class PersonAutocomplete(autocomplete_light.AutocompleteModelBase):
    search_fields = ['^first_name', 'last_name']
autocomplete_light.register(Person, PersonAutocomplete)

In the same fashion, you could have used AutocompleteModelTemplate instead of AutocompleteModelBase. You can see that the inheritance diagram follows the same pattern:

Note

An equivalent of this example would be:

autocomplete_light.register(Person,
    search_fields=['^first_name', 'last_name'])

Overriding the queryset of a model autocomplete to secure an Autocomplete

You can override any method of the Autocomplete class. Filtering choices based on the request user could look like this:

class PersonAutocomplete(autocomplete_light.AutocompleteModelBase):
    search_fields = ['^first_name', 'last_name'])
    model = Person

    def choices_for_request(self):
        if not self.request.user.is_staff:
            self.choices = self.choices.filter(private=False)

        return super(PersonAutocomplete, self).choices_for_request()

# we have specified PersonAutocomplete.model, so we don't have to repeat
# the model class as argument for register()
autocomplete_light.register(PersonAutocomplete)

It is very important to note here, that clean() will raise a ValidationError if a model is selected in a ModelChoiceField or ModelMultipleChoiceField

Note

Use at your own discretion, as this can cause problems when a choice is no longer part of the queryset, just like with django’s Select widget.

Registering the same Autocomplete class for several autocompletes

This code registers an autocomplete with name ContactAutocomplete:

autocomplete_light.register(ContactAutocomplete)

To register two autocompletes with the same class, pass in a name argument:

autocomplete_light.register(ContactAutocomplete, name='Person',
    choices=Person.objects.filter(is_company=False))
autocomplete_light.register(ContactAutocomplete, name='Company',
    choices=Person.objects.filter(is_company=True))