I know there is a new feature in Django 2.0, which is AutocompleteSelect widget in ModelAdmin. I am trying to use it in my custom modelForm but just failed.
Tried like this
#unit is the foreign key to the incident
class AccountForm(forms.ModelForm):
class Meta:
model = Invoice
...
...
widgets = { 'incident':widgets.AutocompleteSelect(Invoice._meta.get_field('incident').remote_field, admin.site)
}
...
#Invoice model
class Invoice(models.Model):
...
incident = models.ForeignKey(Unit, on_delete=models.CASCADE,null=True)
...
Hope anyone can help me. Thanks
CharField() is a Django form field that takes in a text input. It has the default widget TextInput, the equivalent of rendering the HTML code <input type="text" ...> .
The widget in Django will handle the rendering of the HTML elements and extract data from a POST/GET dictionary that corresponds to the same widget. Whenever we specify a field on a Django form, Django uses some default widget appropriate to the data type to be displayed.
A widget is Django's representation of an HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget. The HTML generated by the built-in widgets uses HTML5 syntax, targeting <! DOCTYPE html> .
The AutocompleteSelect widget will not work outside of the admin site. If you are using AccountForm in admin site you can use the following code:
class AccountForm(forms.ModelForm):
...
incident = forms.ModelChoiceField(
queryset= Unit.objects.all(),
widget=AutocompleteSelect(Invoice.incident.field.remote_field, admin.site),
)
...
class Meta:
model = Invoice
fields = [
'incident',
...
]
@admin.register(Invoice)
class InvoiceAdmin(admin.ModelAdmin):
form = AccountForm
AutocompleteSelect
has 2 required args, rel
and admin_site
. The rel
is used to extract the model used to query the data from and relates to an attribute on a ForeignKey or ManyToManyField. Since I wanted to use this on a field that wasn't actually a ForeignKey, I needed to override a few things to make it work:
class ClientAutocompleteSelect(AutocompleteSelect):
def get_url(self):
model = Client
return reverse(self.url_name % (self.admin_site.name, model._meta.app_label, model._meta.model_name))
class ClientChoiceField(forms.ModelChoiceField):
def __init__(self, queryset=None, widget=None, **kwargs):
if queryset is None:
queryset = Client.objects.all()
if widget is None:
widget = ClientAutocompleteSelect(None, admin.site) # pass `None` for `rel`
super().__init__(queryset, widget=widget, **kwargs)
def to_python(self, value):
return value # just return the client_id and not a Client object
class MyAdminForm(forms.ModelForm):
client_id=ClientChoiceField()
...
This requires that the end user has admin read access to the autocomplete endpoint of the model being queried. You may be able to do more hacking to change that get_url
and use your own endpoint to give search results, though.
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