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?
9 Answers
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.
6
do you need to specify
forms.TextInput
to do theattrs={'placeholder': 'Search'}
declaration ?– JhovaniC@OvedD, I know this is old, but see this question: stackoverflow.com/questions/4341739/…
– NotSimon@OvedD: see my answer for how to do this with a ModelForm
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…
– dspacejsFor chinese, you need the preceeding u like this: {‘placeholder’: u’搜索’}
– shellbye
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'}),
}
2
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.
2
This is great because it avoids having to duplicate the lengthy instantiation of widgets for more complicated objects such as
ModelMultipleChoiceField
. Thanks!Similar spirit:
for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.label
, but I like your constructor method better.– jozxyqk
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})
}
3
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})
@AlbertoChiusole Yes you can, if that’s what you want to do. Thanks for pointing it out.
@DwayneCrooks I suggest you update your #3 as per cdosborn’s solution, because it is way shorter and more readable.
– Marian
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
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})
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"
class FormClass(forms.ModelForm):
class Meta:
model = Book
fields="__all__"
widgets = {
'field_name': forms.TextInput(attrs={'placeholder': 'Type placeholder text here..'}),
}
1
Thank you for this contribution. Could you please add some explanation, in order to help users understand in depth?
– Leonard
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"
})
2
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.
– TylerHI 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?
– halfer