Django Admin: Using a custom widget for only one model field
Solution 1
Create a custom ModelForm for your ModelAdmin and add 'widgets' to its Meta class, like so:
class StopAdminForm(forms.ModelForm):
class Meta:
model = Stop
widgets = {
'approve_ts': ApproveStopWidget(),
}
fields = '__all__'
class StopAdmin(admin.ModelAdmin):
form = StopAdminForm
Done!
Documentation for this is sort of non-intuitively placed in the ModelForm docs, without any mention to it given in the admin docs. See: Creating forms from models
Solution 2
After digging into the admin, model field and form field code, I believe the only way to carry out what I want is by creating a custom model field:
models.py
from django.db import models
from widgets import ApproveStopWidget
class ApproveStopModelField(models.DateTimeField):
pass
class Stop(models.model):
# Other fields
approve_ts = ApproveStopModelField('Approve place', null=True, blank=True)
admin.py
from widgets import ApproveStopWidget
from models import ApproveStopModelField
class StopAdmin(admin.ModelAdmin):
formfield_overrides = {
ApproveStopModelField: {'widget': ApproveStopWidget }
}
It gets the job done.
For the time being, I'll leave the question unanswered because I have the habit of missing the obvious. Perhaps some Django smartypants has a better solution.
Solution 3
Override formfield_for_dbfield like thus:
class VehicleAdmin(admin.ModelAdmin):
search_fields = ["name", "colour"]
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'colour':
kwargs['widget'] = ColourChooserWidget
return super(VehicleAdmin, self).formfield_for_dbfield(db_field,**kwargs)
(credit to http://www.kryogenix.org/days/2008/03/28/overriding-a-single-field-in-the-django-admin-using-newforms-admin/ )
Solution 4
Django's ModelAdmin.get_changelist_form(self, request, **kwargs) will do the trick for the case of list_editable
class StopAdminForm(forms.ModelForm):
class Meta:
model = Stop
widgets = {
'approve_ts': ApproveStopWidget(),
}
class StopAdmin(admin.ModelAdmin):
form = StopAdminForm
#just return the ModelForm class StopAdminForm
def get_changelist_form(self, request, **kwargs):
return StopAdminForm
Refer to Django Official documentation on this topic
I hope this will help
Comments
-
Belmin Fernandez about 4 years
I have a DateTimeField field in my model. I wanted to display it as a checkbox widget in the Django admin site. To do this, I created a custom form widget. However, I do not know how to use my custom widget for only this one field.
The Django documentation explains how to use a custom widget for all fields of a certain type:
class StopAdmin(admin.ModelAdmin): formfield_overrides = { models.DateTimeField: {'widget': ApproveStopWidget } }
This is not granular enough though. I want to change it for only one field.
-
Manel Clos over 11 yearsThere is a clearer solution, using the Meta attribute, here: stackoverflow.com/a/10293970
-
-
Mechanical snail over 11 yearsUnfortunately this only seems to work for the main "edit" page, and not on the list display, whereas
formfield_overrides
works for both. -
Chris Pratt over 11 yearsAnd that warranted a downvote? Please take a moment to read "Vote Down" privilege description: stackoverflow.com/privileges/vote-down. I'm pretty positive my answer doesn't qualify as "an answer that is clearly and perhaps dangerously incorrect".
-
Mechanical snail over 11 yearsThere's a range of opinions: meta.stackexchange.com/a/112664/146243, meta.stackexchange.com/a/46590/146243, meta.stackexchange.com/a/46596/146243.
-
yar over 11 yearsFor those wondering how to integrate this with South, the line you would need for this example is:
from south.modelsinspector import add_introspection_rule add_introspection_rules([], ["^appname\.models\.ApproveStopModelField"])
-
maciek about 9 yearsStarting with Django 1.8 you should add
fields = '__all__'
toMeta
. Vide stackoverflow.com/a/28306347/1161025. -
alxs over 7 yearsNice. Adding a custom
ModelForm
for changing just a widget of one field seems like an overkill to me. -
Sławomir Lenart about 7 years... and
approve_ts
means what? then repeated in next answers. There is no such thing in Django source, either in topic's question. -
Stephen Blair over 6 yearsJust tried this in Django 1.11.5 and it worked perfectly. My model has multiple TextFields and in the Admin change form I needed some to be regular <textarea> elements and others to be TinyMCE rich text editors to accept HTML instead of plain text. The all or nothing 'formfield_overrides' wasn't useful in this scenario.