Upgrading from django-autocomplete-light v1 to v2¶
Please enjoy this v1 to v2 upgrade instructions to upgrade from DAL 1.x to 2.x (documented with love !).
Quick upgrade¶
- the Autocomplete class design hasn’t changed at all.
yourlabsWidget()doesn’t parsesdata-*options the same,- the django/form python code has been re-organised ie.
get_widgets_dict()is gone andautocomplete_light.ModelFormwraps around all features by default. - use
autocomplete_light.ModelForminstead ofautocomplete_light.GenericModelForm- generic foreign keys and django-generic-m2m are supported by default if installed.
Detailed upgrade¶
You should not use widget directly anymore¶
We used to have things like this:
class YourForm(autocomplete_light.GenericModelForm):
user = forms.ModelChoiceField(User.objects.all(),
widget=autocomplete_light.ChoiceWidget('UserAutocomplete'))
related = GenericModelChoiceField(
widget=autocomplete_light.ChoiceWidget(
autocomplete='AutocompleteTaggableItems',
autocomplete_js_attributes={'minimum_characters': 0}))
class Meta:
model = YourModel
This caused several problems:
- broke a DRY principle: if you have defined a
userforeign key and registered an Autocomplete for the model in question,User, then you should not have to repeat this. - broke the DRY principle since you had to set choices on both the
ModelChoiceField and the Autocomplete -
UserAutocompletein this example. - also, validation was done in the widget’s
render()function, mostly for security reasons. Validation is not done in the widget anymore, instead it is done inautocomplete_light.fields.
What should the above code be like ? Well it depends, it could just be:
class YourForm(autocomplete_light.ModelForm):
class Meta:
model = YourModel
If you have registered an Autocomplete for the model that the user
ForeignKey is for, then autocomplete_light.ModelForm will pick it up
automatically.
Assuming you have registered a generic autocomplete,
autocomplete_light.ModelForm will pick it up automatically.
If you want Django’s default behavior back (using a <select> tag), then you
could tell autocomplete_light.ModelForm to not be “autocomplete-aware” for
user as such:
class YourForm(autocomplete_light.ModelForm):
class Meta:
model = YourModel
autocomplete_exclude = ('user',)
autocomplete_light.ModelChoiceField
and
autocomplete_light.GenericModelChoiceField:
class YourForm(autocomplete_light.ModelForm):
user = autocomplete_light.ModelChoiceField('UserAutocomplete')
related = autocomplete_light.GenericModelChoiceField('AutocompleteTaggableItems')
class Meta:
model = YourModel
autocomplete_exclude = ('user',)
You can still override widgets the same way as before, but you should consider the DRY breaking implications (which are not specific to django-autocomplete-light, but Django’s design in general).
Specification of the Autocomplete class to use¶
New rules are:
- if an Autocomplete class was registered for a model then it becomes the default Autocomplete class for autocompletion on that model,
- other Autocomplete classes registered for a model will not be used by default
You can still define the Autocomplete class you want in the field definition:
class FooForm(autocomplete_light.ModelForm):
bar = autocomplete_light.ModelChoiceField('SpecialBarAutocomplete')
class Meta:
model = Foo
But this will break some break django DRY logic. Instead, this won’t break DRY:
class FooForm(autocomplete_light.ModelForm):
class Meta:
model = Foo
autocomplete_names = {'bar': 'SpecialBarAutocomplete'}
Python class re-organisation¶
Form classes like FixedModelform or GenericModelForm were
renamed. But if you can, just inherit from
autocomplete_light.ModelForm instead.
Generic field classes were moved from
autocomplete_light.contrib.generic_m2m into
autocomplete_light.fields: just import
autocomplete_light.GenericModelChoiceField and
autocomplete_light.GenericModelMultipleChoiceField <autocomplete_light.fields.GenericModelMultipleChoiceField.
Deprecation of autocomplete_js_attributes and widget_js_attributes¶
In the past, we used autocomplete_js_attributes and
widget_js_attributes. Those are deprecated and HTML data
attributes should be used instead.
For example:
class PersonAutocomplete(autocomplete_light.AutocompleteModelBase):
model = Person
autocomplete_js_attributes = {
'minimum_characters': 0,
'placeholder': 'foo',
}
widget_js_attributes = {'max_values': 3}
Should now be:
class PersonAutocomplete(autocomplete_light.AutocompleteModelBase):
model = Person
attrs = {
'data-autcomplete-minimum-characters': 0,
'placeholder': 'foo',
}
widget_attrs = {'data-widget-maximum-values': 3}
As you probably understand already magic inside
autocomplete_js_attributes and widget_js_attributes is gone,
we’re just setting plain simple HTML attributes now with attrs.
Also notice the other two differences which are detailed below:
max-valueswas renamed tomaximum-values(see below)data-autocomplete-placeholderis gone in favor of HTML5placeholderattribute (see below)
max-values was renamed to maximum-values¶
For consistency with one of my naming conventions which is: no abbreviations.
data-autocomplete-placeholder is gone in favor of HTML5 placeholder attribute¶
It made no sense to keep data-autocomplete-placeholder since we now
have the HTML5 placeholder attribute.
Widget template changes¶
This is a side effect from the deprecation of
autocomplete_js_attributes and widget_js_attributes.
This:
<span class="autocomplete-light-widget {{ name }}
{% if widget.widget_js_attributes.max_values == 1 %}single{% else %}multiple{% endif %}"
id="{{ widget.html_id }}-wrapper"
{{ widget.widget_js_attributes|autocomplete_light_data_attributes }}
{{ widget.autocomplete_js_attributes|autocomplete_light_data_attributes:'autocomplete-' }}
>
Is now:
<span id="{{ widget.html_id }}-wrapper" {{ widget_attrs }} >
Script changes¶
.yourlabsWidget() used to parse data-* attributes:
data-foo-barused to set the JS attributeyourlabs.Widget.fooBar,data-autocomplete-foo-barused to set the JS attributeyourlabs.Widget.autocomplete.fooBar.
Now:
.yourlabsWidget()parsesdata-widget-*attributes and,.yourlabsAutocomplete()parsesdata-autocomplete-*on the ``<input />`` !
So this:
<span class="autocomplete-light-widget" data-autocomplete-foo-bar="2" data-foo-bar="3">
<input .. />
Becomes:
<span class="autocomplete-light-widget" data-widget-foo-bar="3">
<input data-autocomplete-foo-bar="2" ... />
.choiceDetail and .choiceUpdate were renamed to .choice-detail and .choice-update¶
This makes the CSS class names standard.