Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use autocompleteselect widget in a modelform

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

like image 207
Cybershoe Avatar asked Apr 26 '19 04:04

Cybershoe


People also ask

Which code will give us a textarea form field in Django?

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" ...> .

What is the significance of introducing custom widgets in Django?

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.

How do I use widgets in Django?

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> .


2 Answers

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
like image 196
Erez Haim Avatar answered Oct 12 '22 14:10

Erez Haim


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.

like image 22
Tim Tisdall Avatar answered Oct 12 '22 13:10

Tim Tisdall