2

I'd like to add placeholder text to a field in the Django Admin change form. In a regular ModelForm you can do this by overriding the field's widget or by modifying self.fields['my_field'].widget in the ModelForm __init__() method. How do I do something similar for a Django Admin?

Ben Sturmfels
  • 1,303
  • 13
  • 22

4 Answers4

3

The documented way is to override get_form():

The base implementation uses modelform_factory() to subclass form, modified by attributes such as fields and exclude.

If you look at the docs for modelform_factory you'll see that you can pass widgets as kwarg. So this should work:

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        kwargs['widgets'] = {
            'name': forms.TextInput(attrs={'placeholder': 'e.g. John Doe'})
        }
        return super().get_form(request, obj, **kwargs)

or, if you want to be sure you're not overriding any widgets (if you're inheriting from a subclass of ModelAdmin):

 kwargs['widgets'] = kwargs.get('widgets', {})
 kwargs['widgets'].update({'name': ...})
dirkgroten
  • 20,112
  • 2
  • 29
  • 42
1

Override the render_change_form() method on your ModelAdmin, which provides access to the form instance:

class Address(model.Model):
    street = models.CharField(max_length=50)

class AddressAdmin(admin.ModelAdmin):
    def render_change_form(self, request, context, *args, **kwargs):
        form_instance = context['adminform'].form
        form_instance.fields['street'].widget.attrs['placeholder'] = 'Your street'
        return super().render_change_form(request, context, *args, **kwargs)

This approach would be the same for other field attributes like attributes like autocomplete, autofocus, min, max, required, type or pattern. You also have access to context["original"] which provides the model instance, in case you'd like to change the behavior based on the model instance.

The source code is the best reference for this: https://docs.djangoproject.com/en/2.2/_modules/django/contrib/admin/options/#ModelAdmin

Ben Sturmfels
  • 1,303
  • 13
  • 22
  • Where is `render_change_form` documented? It's not part of the methods documented [here](https://docs.djangoproject.com/en/stable/ref/contrib/admin/) so it's not guaranteed to remain stable. – dirkgroten Oct 03 '19 at 15:08
  • 1
    There's no reason to believe that `render_change_form` is in any way unstable. With `get_form` you're working with the form class, where in `render_change_form` you're working with the form instance. Access to the form instance allows you to to modify the widget, rather than having to replace it. It also provides access to the model instance in case you want to customise the form dynamically (which is very useful, but another story). – Ben Sturmfels Oct 04 '19 at 01:18
  • I meant unstable in the sense that any changes to its behaviour or signature (or even removal if the rendering logic is changed) won’t be mentioned in release notes of future django releases because it’s not part of the “official” ModelAdmin API. – dirkgroten Oct 04 '19 at 07:38
1

This is a way of doing it without having to manually add placeholder text to each field:

admin.py

from django import forms


class MyModelAdmin(admin.ModelAdmin):
    def render_change_form(self, request, context, *args, **kwargs):
        form_instance = context['adminform'].form
        for key, field in form_instance.fields.items():
            if isinstance(field.widget, (forms.TextInput, forms.EmailInput)):
                field.widget.attrs.update({'placeholder': field.label})
        return super().render_change_form(request, context, *args, **kwargs)
John R Perry
  • 3,916
  • 2
  • 38
  • 62
1

Another way to do this is:

class MyModelAdmin(model.ModelAdmin):   
    def get_form(self, request, obj=None, **kwargs):
     #--> Get form 
        form = super().get_form(request, obj, **kwargs)
     #--> Add placeholder for field
        form.base_fields['the_field_name'].widget.attrs['placeholder'] = "My_Place_Holder_Text"
     #--> Return form
        return form
    #---
#---

This is similar to the answer of dirkgroten. The advantage here is that there is no need to worry about the widget used for the field.

kbr85
  • 1,416
  • 12
  • 27