django-autocomplete-light

repository·master·Indexed 23 days ago

https://github.com/yourlabs/django-autocomplete-light

A Django library providing advanced autocomplete widgets for forms, supporting native web components via dal_alight and Select2.js via dal_select2. It features deep integration for complex Django field types, including Generic Foreign Keys, django-taggit, and ContentTypes. Key capabilities include filtering results based on other form fields (forwarding), on-the-fly object creation, and support for both QuerySet-backed and plain Python list results.

Tokens
23.7K
Snippets
50
Records
122
Agent score
81%

What's inside django-autocomplete-light

  1. How Select2 autocompletes work

    master

    An autocomplete implementation in DAL using Select2 consists of three essential components:

    1. A Widget: A Django form widget compatible with the model field that handles the initial rendering.
    2. JavaScript Initialization: Code that initializes the Select2 widget to trigger the autocomplete behavior.
    3. An Autocomplete View: A Django view used by the widget's JavaScript to fetch suggestion results via AJAX.

    Warning: Select2 has known issues with object lifecycle management in jQuery. For new projects, it is recommended to use the Autocomplete-Light Web Component instead.

  2. Types of forwarded values in DAL

    master

    When forwarding a field, DAL's JavaScript logic determines the data type sent to the server based on the following rules:

    • Boolean: If there is exactly one field with the given name and it is a checkbox without an HTML value attribute, the value forwarded is a boolean indicating if it is checked.
    • List of Strings:
      • If there is exactly one field with the given name and it has the multiple HTML attribute.
      • If there are one or more fields with the given name and all of them are checkboxes with an HTML value attribute (the list contains the values of the checked checkboxes).
    • String: Otherwise, the field value is forwarded as a string.
  3. Compare dal_alight vs dal_select2 frontends

    master

    Django-autocomplete-light provides two distinct frontend implementations: dal_alight and dal_select2. While they share the same Django-side base classes (like BaseQuerySetView and ViewMixin), they differ significantly in their technical implementation and payload.

    dal_alight

    • Response Format: Returns HTML fragments (e.g., <div data-value="pk">Label</div>).
    • JS Payload: Uses an autocomplete-light web component (~15 KB) and a DAL adapter (~11 KB).
    • Dependencies: No jQuery required. Uses native Custom Elements v1.
    • Best for: Modern stacks (HTMX, API-only), minimizing JS payload, and projects where the server should own result rendering via HTML fragments.

    dal_select2

    • Response Format: Returns JSON (e.g., {results:[{id, text, selected_text}], pagination:{more}}).
    • JS Payload: Uses Select2 4.x (~170 KB) plus jQuery and a DAL glue (~5 KB).
    • Dependencies: Requires jQuery.
    • Best for: When you need advanced features like token separators, distinct selected-item labels, or rich HTML templates that differ between the dropdown and the selection.
  4. Configure Select2 Tags mode in DAL v5

    master

    DAL's Select2 integration now defines a createTag function for tags mode and marks client-created tags with newTag: true. The result template shows new tags as Create "value" while the selected value remains the raw tag text.

    If you have copied or replaced autocomplete_light/select2.js, you must add equivalent handling for createTag:

    var createTagFn = null;
    if (use_tags) {
        createTagFn = function(params) {
            var term = $.trim(params.term);
            if (!term) return null;
            return {id: term, text: term, newTag: true};
        };
    }
    
    $element.select2({
        tags: use_tags,
        createTag: createTagFn,
        // keep your other DAL options
    });

    When overriding templateResult or templateSelection, you must handle item.newTag (to display the create label) and item.create_id (the server-side marker).

  5. When to use dal_alight

    master

    Choose the dal_alight frontend if your project meets any of the following criteria:

    • No jQuery: You are using a modern frontend stack (like HTMX) and want to avoid jQuery.
    • Minimal Payload: You want to minimize the JavaScript footprint and eliminate third-party dependencies.
    • Server-Side Rendering: You prefer the server to control result rendering via HTML fragments, which is useful if labels require complex Django template logic or permission checks.
    • Max-Choices Enforcement: You want client-side enforcement of a maximum number of selections (using the max-choices attribute), where the oldest selection is automatically evicted when the cap is exceeded.
    • Web Components: You are building in a Custom Elements or Shadow-DOM ecosystem.
  6. Automate autocomplete fields with djhacker

    master

    If you want to integrate an autocomplete view and form field automatically throughout Django (including the admin) without manually defining custom ModelForms every time, use the djhacker library.

    import djhacker  # don't forget to pip install djhacker
    from django import forms
    
    djhacker.formfield(
        Person.birth_country,
        forms.ModelChoiceField,
        widget=autocomplete.ModelSelect2(url='country-autocomplete')
    )
  7. Filter autocomplete results based on other form fields (forwarding)

    master

    You can restrict the results of an autocomplete widget based on the values of other fields in the same form using the forward argument.

    1. In the Form: Add the names of the fields you want to pass to the autocomplete request to the forward list in the widget configuration.
    2. In the View: Access the forwarded values via self.forwarded. This is a dictionary containing the current values of the specified fields.

    This mechanism is frontend-agnostic and works across different DAL frontends.

    # 1. Configure the form to forward the 'continent' field
    class PersonForm(forms.ModelForm):
        continent = forms.ChoiceField(choices=CONTINENT_CHOICES)
    
        class Meta:
            model = Person
            fields = ('__all__',)
            widgets = {
                'birth_country': autocomplete.ModelAlight(
                    url='country-autocomplete',
                    forward=['continent'],
                )
            }
    
    # 2. Use the forwarded value in the view
    class CountryAutocomplete(autocomplete.AlightQuerySetView):
        def get_queryset(self):
            qs = Country.objects.all()
            # Access the value via self.forwarded
            continent = self.forwarded.get('continent', None)
            if continent:
                qs = qs.filter(continent=continent)
            if self.q:
                qs = qs.filter(name__istartswith=self.q)
            return qs
  8. Register the autocomplete view in URLs

    master

    Once the view is created, you must register it in your project's urlpatterns with a named URL. This name is used by the widget to know where to send AJAX requests.

    from django.urls import path
    from your_countries_app.views import CountryAutocomplete
    
    urlpatterns = [
        path(
            'country-autocomplete/',
            CountryAutocomplete.as_view(),
            name='country-autocomplete',
        ),
    ]
  9. Migrate from dal_select2 to dal_alight

    master

    To migrate an existing project from dal_select2 to dal_alight, you must replace Select2 class names with their Alight counterparts across your views, widgets, and form fields.

    Key architectural changes:

    • Dependency Change: dal_alight uses native Web Components and has no external library dependencies (jQuery is no longer required).
    • Response Format: Unlike dal_select2 which returns JSON, dal_alight views return HTML fragments.
    • Static Files: Replace dal_select2 media with dal_alight media.
    • Admin: ModelAdmin.form assignment remains identical.