Dependencies between autocompletes¶
This means that the selected value in an autocomplete widget is used to filter choices from another autocomplete widget.
This page drives through the example in autocomplete_light/example_apps/dependant_autocomplete/.
Specifications¶
Consider such a model:
from django.db import models
class Dummy(models.Model):
parent = models.ForeignKey('self', null=True, blank=True)
country = models.ForeignKey('cities_light.country')
region = models.ForeignKey('cities_light.region')
def __unicode__(self):
return '%s %s' % (self.country, self.region)
And we want two autocompletes in the form, and make the “region” autocomplete to be filtered using the value of the “country” autocomplete.
Autocompletes¶
Register an Autocomplete for Region that is able to use ‘country_id’ GET parameter to filter choices:
import autocomplete_light.shortcuts as autocomplete_light
from cities_light.models import Country, Region
autocomplete_light.register(Country, search_fields=('name', 'name_ascii',),
autocomplete_js_attributes={'placeholder': 'country name ..'})
class AutocompleteRegion(autocomplete_light.AutocompleteModelBase):
autocomplete_js_attributes={'placeholder': 'region name ..'}
def choices_for_request(self):
q = self.request.GET.get('q', '')
country_id = self.request.GET.get('country_id', None)
choices = self.choices.all()
if q:
choices = choices.filter(name_ascii__icontains=q)
if country_id:
choices = choices.filter(country_id=country_id)
return self.order_choices(choices)[0:self.limit_choices]
autocomplete_light.register(Region, AutocompleteRegion)
Javascript¶
Actually, a normal modelform is sufficient. But it was decided to use Form.Media to load the extra javascript:
import autocomplete_light.shortcuts as autocomplete_light
from django import forms
from .models import Dummy
class DummyForm(autocomplete_light.ModelForm):
class Media:
"""
We're currently using Media here, but that forced to move the
javascript from the footer to the extrahead block ...
So that example might change when this situation annoys someone a lot.
"""
js = ('dependant_autocomplete.js',)
class Meta:
model = Dummy
exclude = []
That’s the piece of javascript that ties the two autocompletes:
$(document).ready(function() {
$('body').on('change', '.autocomplete-light-widget select[name$=country]', function() {
var countrySelectElement = $(this);
var regionSelectElement = $('#' + $(this).attr('id').replace('country', 'region'));
var regionWidgetElement = regionSelectElement.parents('.autocomplete-light-widget');
// When the country select changes
value = $(this).val();
if (value) {
// If value is contains something, add it to autocomplete.data
regionWidgetElement.yourlabsWidget().autocomplete.data = {
'country_id': value[0],
};
} else {
// If value is empty, empty autocomplete.data
regionWidgetElement.yourlabsWidget().autocomplete.data = {}
}
// example debug statements, that does not replace using breakbpoints and a proper debugger but can hel
// console.log($(this), 'changed to', value);
// console.log(regionWidgetElement, 'data is', regionWidgetElement.yourlabsWidget().autocomplete.data)
})
});
Conclusion¶
Again, there are many ways to acheive this. It’s just a working example you can test in the demo, you may copy it and adapt it to your needs.