In the Django admin interface you can set a field to be a autocomplete field, e.g.:
autocomplete_fields = ('countries', )
This works great for admin pages, how does one use the autocomplete field in a custom view/form? My research points towards django-autocomplete-light, but it seems non-ideal to install a 3rd party package when Django already has the functionality built-in.
Indeed it is possible to use the select2 from the admin.
You simply need to use the AutocompleteSelect
widget. The AutocompleteSelect widget expects an relation and an admin site.
If you have model A
that has a ForeignKey field pointing to model B
for which you want to use the AutocompleteSelect, you simply can use (as suggested by cuto).
from django.contrib.admin.widgets import AutocompleteSelect
from myapp.model import ModelA, ModelB
from django.contrib import admin
class MyForm(form.Form):
model_b = forms.ModelChoiceField(
queryset=ModelB.objects.all(),
widget=AutocompleteSelect(ModelA._meta.get_field('model_b').remote_field, admin.AdminSite)
)
As I did not have a relation I used a FakeRelation
class, as only the model property is used by the get_url(self)
function.
The usage of the AutocompleteSelect widget is bound to the same condition as the the usage of the autocomplete_fields widget.
from django.contrib.admin.widgets import AutocompleteSelect
from django.contrib import admin
from django import forms
from myapp.models import countries
class FakeRelation:
def __init__(self, model):
self.model = model
class CustomAutocompleteSelect (AutocompleteSelect):
def __init__(self, model, admin_site, attrs=None, choices=(), using=None):
rel = FakeRelation(model)
super().__init__(rel, admin_site, attrs=attrs, choices=choices, using=using)
class PreventionPlanForm(form.Form):
DateFrom = forms.DateField(label="From")
DateTo = forms.DateField(label="To")
PE1_Name = forms.ModelChoiceField(
queryset=countries.objects.all(),
widget=CustomAutocompleteSelect(countries, admin.AdminSite)
)
As jenniwren pointed out: Make sure to load the correct Javascripts/CSS files in your template (path could be subject to change in different django versions):
The FakeRelation solution proposed before does not work anymore with Django 2.2 which requires a field instance for the AutocompleteSelect constructor.
I had a suitable field in my project, so I could use it, but had to pass a field instance instead of a relation. Here is the code for a custom AutocompleteSelect which also add the option to pass a specific placeholder to Select2:
class CustomAutocompleteSelect(AutocompleteSelect):
def __init__(self, field, prompt="", admin_site=None, attrs=None, choices=(), using=None):
self.prompt = prompt
super().__init__(field, admin_site, attrs=attrs, choices=choices, using=using)
def build_attrs(self, base_attrs, extra_attrs=None):
attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs)
attrs.update({
'data-ajax--delay': 250,
'data-placeholder': self.prompt,
'style': 'width: 30em;'
})
return attrs
class AddLittermateForm(forms.Form):
new_littermate = forms.ModelChoiceField(
queryset=Dog.objects.all(),
widget=CustomAutocompleteSelect(LitterDog._meta.get_field(
'dog'), "Search for a littermate here", admin.site)
)
If one did not have a model with a suitable relation, they would have to declare one that is not managed:
...
class Meta:
managed = False
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With