[python] How do I add a placeholder on a CharField in Django?

Take this very simple form for example:

class SearchForm(Form):
    q = forms.CharField(label='search')

This gets rendered in the template:

<input type="text" name="q" id="id_q" />

However, I want to add the placeholder attribute to this field with a value of Search so that the HTML would look something like:

<input type="text" name="q" id="id_q" placeholder="Search" />

Preferably I would like to pass the placeholder value in to CharField in the form class through a dictionary or something like:

q = forms.CharField(label='search', placeholder='Search')

What would be the best way to accomplish this?

This question is related to python django django-forms

The answer is


It's undesirable to have to know how to instantiate a widget when you just want to override its placeholder.

    q = forms.CharField(label='search')
    ...
    q.widget.attrs['placeholder'] = "Search"

The other methods are all good. However, if you prefer to not specify the field (e.g. for some dynamic method), you can use this:

def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['email'].widget.attrs['placeholder'] = self.fields['email'].label or '[email protected]'

It also allows the placeholder to depend on the instance for ModelForms with instance specified.


Most of the time I just wish to have all placeholders equal to the verbose name of the field defined in my models

I've added a mixin to easily do this to any form that I create,

class ProductForm(PlaceholderMixin, ModelForm):
    class Meta:
        model = Product
        fields = ('name', 'description', 'location', 'store')

And

class PlaceholderMixin:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        field_names = [field_name for field_name, _ in self.fields.items()]
        for field_name in field_names:
            field = self.fields.get(field_name)
            field.widget.attrs.update({'placeholder': field.label})

Great question. There are three solutions I know about:

Solution #1

Replace the default widget.

class SearchForm(forms.Form):  
    q = forms.CharField(
            label='Search',
            widget=forms.TextInput(attrs={'placeholder': 'Search'})
        )

Solution #2

Customize the default widget. If you're using the same widget that the field usually uses then you can simply customize that one instead of instantiating an entirely new one.

class SearchForm(forms.Form):  
    q = forms.CharField(label='Search')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['q'].widget.attrs.update({'placeholder': 'Search'})

Solution #3

Finally, if you're working with a model form then (in addition to the previous two solutions) you have the option to specify a custom widget for a field by setting the widgets attribute of the inner Meta class.

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }

class FormClass(forms.ModelForm):
    class Meta:
        model = Book
        fields = '__all__'
        widgets = {
            'field_name': forms.TextInput(attrs={'placeholder': 'Type placeholder text here..'}),
        }

After looking at your method, I used this method to solve it.

class Register(forms.Form):
    username = forms.CharField(label='???', max_length=32)
    email = forms.EmailField(label='??', max_length=64)
    password = forms.CharField(label="??", min_length=6, max_length=16)
    captcha = forms.CharField(label="???", max_length=4)

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for field_name in self.fields:
        field = self.fields.get(field_name)
        self.fields[field_name].widget.attrs.update({
            "placeholder": field.label,
            'class': "input-control"
        })

For a ModelForm, you can use the Meta class thus:

from django import forms

from .models import MyModel

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'Name'}),
            'description': forms.Textarea(
                attrs={'placeholder': 'Enter description here'}),
        }

You can use this code to add placeholder attr for every TextInput field in you form. Text for placeholders will be taken from model field labels.

class PlaceholderDemoForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PlaceholderDemoForm, self).__init__(*args, **kwargs)
        for field_name in self.fields:
            field = self.fields.get(field_name)  
            if field:
                if type(field.widget) in (forms.TextInput, forms.DateInput):
                    field.widget = forms.TextInput(attrs={'placeholder': field.label})

    class Meta:
        model = DemoModel

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to django

How to fix error "ERROR: Command errored out with exit status 1: python." when trying to install django-heroku using pip Pylint "unresolved import" error in Visual Studio Code Is it better to use path() or url() in urls.py for django 2.0? Unable to import path from django.urls Error loading MySQLdb Module 'Did you install mysqlclient or MySQL-python?' ImportError: Couldn't import Django Django - Reverse for '' not found. '' is not a valid view function or pattern name Class has no objects member Getting TypeError: __init__() missing 1 required positional argument: 'on_delete' when trying to add parent table after child table with entries How to switch Python versions in Terminal?

Examples related to django-forms

__init__() got an unexpected keyword argument 'user' What's the best way to store Phone number in Django models How to create Password Field in Model Django Django Forms: if not valid, show form with error message What is the equivalent of "none" in django templates? How to create password input field in django Python regex for integer? Change a Django form field to a hidden field CSS styling in Django forms Django: Model Form "object has no attribute 'cleaned_data'"