Opened 6 years ago

Closed 6 years ago

#29901 closed Cleanup/optimization (fixed)

InlineModelAdmin.get_formset() doesn't work with custom widgets passed in kwargs

Reported by: Javier Matos Odut Owned by: Javier Matos Odut
Component: contrib.admin Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

InlineModelAdmin class has get_formset method that will create a formset based on the parameters given.

django.contrib.admin.options.InlineModelAdmin.get_formset is called with widgets and then:

django.forms.models.inlineformset_factory (Ok here as widgets are passed)
django.forms.models.modelformset_factory (Ok here as widgets are passed)
django.forms.models.modelform_factory (Ok here as widgets are passed)
django.forms.models.ModelFormMetaclass.new (Ok as widgets are passed as attrs)
django.forms.models.fields_for_model (Ok here too)
django.contrib.admin.options.BaseModelAdmin.formfield_for_dbfield (Ok here too as widget is received in kwargs)

Then here comes the problem:

django.contrib.admin.options.BaseModelAdmin.formfield_for_foreignkey

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """
        Get a form Field for a ForeignKey.
        """
        db = kwargs.get('using')

        if db_field.name in self.get_autocomplete_fields(request):
            kwargs['widget'] = AutocompleteSelect(db_field.remote_field, self.admin_site, using=db)
        elif db_field.name in self.raw_id_fields:
            kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
        elif db_field.name in self.radio_fields:
            kwargs['widget'] = widgets.AdminRadioSelect(attrs={
                'class': get_ul_class(self.radio_fields[db_field.name]),
            })
            kwargs['empty_label'] = _('None') if db_field.blank else None

        if 'queryset' not in kwargs:
            queryset = self.get_field_queryset(db, db_field, request)
            if queryset is not None:
                kwargs['queryset'] = queryset

        return db_field.formfield(**kwargs)

This code just ignores the widget sent.

How to fix this? Just change that method to the following:

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        """
        Get a form Field for a ForeignKey.
        """
        db = kwargs.get('using')

        if 'widget' not in kwargs:
            if db_field.name in self.get_autocomplete_fields(request):
                kwargs['widget'] = AutocompleteSelect(db_field.remote_field, self.admin_site, using=db)
            elif db_field.name in self.raw_id_fields:
                kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
            elif db_field.name in self.radio_fields:
                kwargs['widget'] = widgets.AdminRadioSelect(attrs={
                    'class': get_ul_class(self.radio_fields[db_field.name]),
                })
                kwargs['empty_label'] = _('None') if db_field.blank else None

        if 'queryset' not in kwargs:
            queryset = self.get_field_queryset(db, db_field, request)
            if queryset is not None:
                kwargs['queryset'] = queryset

        return db_field.formfield(**kwargs)

With if 'widget' not in kwargs I let any widget set to be used by default instead of assigning a new one. That is the only change to fix it. This way now I am able to use my TabularInline and override get_formset to show my fields with custom widgets.

Attachments (1)

mypatch.diff (1.7 KB ) - added by Javier Matos Odut 6 years ago.
Patch to fix the issue

Download all attachments as: .zip

Change History (4)

by Javier Matos Odut, 6 years ago

Attachment: mypatch.diff added

Patch to fix the issue

comment:1 by Tim Graham, 6 years ago

Easy pickings: unset
Needs tests: set
Summary: InlineModelAdmin.get_formset do not work with custom widgets passed in kwargsInlineModelAdmin.get_formset() doesn't work with custom widgets passed in kwargs
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Can you add a test to your PR and then uncheck "Needs tests" on the ticket?

comment:2 by Javier Matos Odut, 6 years ago

Needs tests: unset
Owner: changed from nobody to Javier Matos Odut
Status: newassigned
Version: 2.1master

comment:3 by Tim Graham <timograham@…>, 6 years ago

Resolution: fixed
Status: assignedclosed

In 3d4d0a2:

Fixed #29901 -- Allowed overriding an autocomplete/raw_id_fields/radio_fields widget with ModelAdmin.get_formset().

Note: See TracTickets for help on using tickets.
Back to Top