How do I add a placeholder on a CharField in Django?

137,155

Solution 1

Look at the widgets documentation. Basically it would look like:

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

More writing, yes, but the separation allows for better abstraction of more complicated cases.

You can also declare a widgets attribute containing a <field name> => <widget instance> mapping directly on the Meta of your ModelForm sub-class.

Solution 2

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'}),
        }

Solution 3

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.

Solution 4

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})
        }

Solution 5

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
Share:
137,155

Related videos on Youtube

Joelbitar
Author by

Joelbitar

I like programming, I also like beer. Big fan of Android, Python and free software. I wish there were more hours on a day to write more code, there is always some project to finish.

Updated on September 28, 2020

Comments

  • Joelbitar
    Joelbitar over 3 years

    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?

  • NotSimon
    NotSimon over 10 years
    @OvedD, I know this is old, but see this question: stackoverflow.com/questions/4341739/…
  • Hamish Downer
    Hamish Downer over 10 years
    @OvedD: see my answer for how to do this with a ModelForm
  • donturner
    donturner almost 10 years
    This is great because it avoids having to duplicate the lengthy instantiation of widgets for more complicated objects such as ModelMultipleChoiceField. Thanks!
  • jozxyqk
    jozxyqk over 9 years
    Similar spirit: for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.label, but I like your constructor method better.
  • Will S
    Will S about 8 years
    Note that in this case you cannot specify the field in the class body.
  • dspacejs
    dspacejs almost 7 years
    It's pretty stupid that you have to specify a widget to add a placeholder. You should be able to edit widget attributes without overriding the entire widget...
  • JxAxMxIxN
    JxAxMxIxN almost 7 years
    This was the easiest method for me - and it was nice that all the other attributes (i.e. required) were still automatically added without me having to specify them.
  • shellbye
    shellbye over 6 years
    For chinese, you need the preceeding u like this: {'placeholder': u'搜索'}
  • Alberto Chiusole
    Alberto Chiusole about 6 years
    I was about to write a solution as yours #2. I'd like to add that you can apply operations on all the fields by iterating over self.fields, e.g.: for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
  • Dwayne Crooks
    Dwayne Crooks about 6 years
    @AlbertoChiusole Yes you can, if that's what you want to do. Thanks for pointing it out.
  • Marian
    Marian over 4 years
    @DwayneCrooks I suggest you update your #3 as per cdosborn's solution, because it is way shorter and more readable.
  • TylerH
    TylerH about 4 years
    Please note that content must be in English on Stack Overflow. Aside from that, this appears to be a "me too" post, rather than an answer to the question posed above.
  • halfer
    halfer about 4 years
    I would say that "me too" posts are OK if they add more detail. What about this approach is different to any of the others? What is the technique or essential learning here?
  • Leonard
    Leonard over 3 years
    Thank you for this contribution. Could you please add some explanation, in order to help users understand in depth?

Related