How to I prevent Django Admin for overriding the custom widget for a custom field?

I have a model field, a form field, and a widget that I am using in an app. The details of the code don't matter. The key is that the field correctly renders in regular forms but is overridden in admin.

Here is some pseudo-code of what the field basically looks like:

class SandwichWidget(forms.Widget):
    template_name = 'sandwichfield/widgets/sandwichfield.html'

    def __init__(self, attrs=None, date_format=None, time_format=None):
        widgets = (
            NumberInput(),
            Select(choices=FILLING_CHOICES),
            NumberInput(),
        )
        super(SandwichWidget, self).__init__(widgets, attrs)

    def decompress(self, value):
        if value:
            value = Sandwich(value)
            return [
                value.top,
                value.middle,
                value.bottom
            ]
        return [None, None, None]


class SandwichFormField(forms.MultiValueField):
    widget = SandwichWidget

    def __init__(self, input_date_formats=None, input_time_formats=None, *args, **kwargs):
        fields = (
            forms.IntegerField(),
            forms.CharField(),
            forms.IntegerField(),
        )
        super(SandwichFormField, self).__init__(fields, *args, **kwargs)


class SandwichField(models.PositiveIntegerField):

    def get_internal_type(self):
        return 'IntegerField'

    def formfield(self, *args, **kwargs):
        defaults={'form_class': SandwichFormField}
        defaults.update(kwargs)
        return super(SandwichField, self).formfield(*args, **defaults)

It apparently happens because of this line in django/contrib/admin/options.py which specifies the override of the models.IntegerField should be widgets.AdminIntegerFieldWidget. Because models.PositiveIntegerField inherits from models.IntegerField, and because line 181 loops over all subclasses of the field, it seems like there is no way to prevent the widget from being overridden in admin.

This is a real problem, because I use this custom field, with its custom widget, all over my site and throughout admin, and I do not want to have put in a custom value for override_fields every time I want to use the field. Ideally, developers should be able to use the custom field without having to provide a custom admin each time.

Currently I'm inheriting from forms.PositiveIntegerField because when stored and retrieved from the database, it is a positive integer, and I want to take advantage of all of the coding already in place for handling positive integer values.

Currently it looks like the only solution is changing my field to inherit from models.Field and then copying and pasting all of the PositiveIntegerField and IntegerField functionality from the django code. Is there an alternative to this?

Of course, I can always have my formfield ignore whatever widget is sent to it and always use the custom widget, but this raises a problem when I actively want to override the widget, which absolutely could happen. I just don't want admin to override my widget.

728x90

1 Answers How to I prevent Django Admin for overriding the custom widget for a custom field?

In your model admin, you need to add those widgets in formfield_overrides. For example like this:

class BaseModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.CharField: {'widget': forms.Textarea},
    }

Now you can sub-class all of your model admins from this class and don't have to write redundant code for overrides.

1 weeks ago