Ben Sturmfels
Ben Sturmfels

Reputation: 1483

How to add placeholder text to a Django Admin field

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?

Upvotes: 2

Views: 4374

Answers (5)

Su Kai
Su Kai

Reputation: 31

from django import forms
from django.contrib import admin
from django.contrib.admin.helpers import ActionForm


class CustomForm(ActionForm):
    subject = forms.CharField(label='Label:', widget=admin.widgets.AdminTextInputWidget(attrs={'placeholder': 'my placeholder'}))


@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    action_form = CustomForm

Upvotes: 1

kbr85
kbr85

Reputation: 1446

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.

Upvotes: 1

John R Perry
John R Perry

Reputation: 4202

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)

Upvotes: 1

Ben Sturmfels
Ben Sturmfels

Reputation: 1483

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

Upvotes: 1

dirkgroten
dirkgroten

Reputation: 20702

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': ...})

Upvotes: 4

Related Questions