如何在Django的CharField中添加占位符?

236

以这个非常简单的表单为例:

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

这将在模板中呈现:

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

不过,我想在这个字段中添加placeholder属性,并设置一个值为Search,这样HTML看起来会像这样:

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

最好的情况是我希望通过一个字典或类似的东西将占位符的值传递到表单类中的 CharField

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

如何最好地实现这个目标?

9个回答

346

请查看小部件文档。基本上它看起来像这样:

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

更多的代码编写,但是这种分离允许更好地抽象出更复杂的情况。

您还可以在ModelForm子类的Meta上直接声明一个包含<field name> => <widget instance>映射的widgets属性。


你需要指定 forms.TextInput 来进行 attrs={'placeholder': 'Search'} 的声明吗? - JhovaniC
1
@OvedD,我知道这很老了,但请看这个问题:https://dev59.com/Vm855IYBdhLWcg3wcz1h - NotSimon
2
@OvedD:请看我的答案,了解如何使用ModelForm完成此操作。 - Hamish Downer
2
很愚蠢的是,你必须指定一个小部件才能添加占位符。你应该能够在不覆盖整个小部件的情况下编辑小部件属性... - Daniel
1
对于中文,您需要像这样使用前缀u:{'placeholder': u'搜索'} - shellbye
1
@shellbye 这只在 Python2 中才是真的,而你在2017年可能不应该使用,现在绝对不应该再使用了。 - Adam Barnes

72

对于一个ModelForm,你可以使用Meta类如下:

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

请注意,在这种情况下,您不能在类主体中指定字段。 - Will S
这对我来说是最简单的方法 - 而且很好的是,所有其他属性(即必需的)仍然自动添加,而无需我指定它们。 - JxAxMxIxN

57

其他方法都很好。然而,如果您不想指定字段(例如某些动态方法),可以使用这个:

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

对于指定了实例的ModelForms,它还允许占位符依赖于实例。


9
这很好,因为它避免了为更复杂的对象(如“ModelMultipleChoiceField”)复制冗长的小部件实例化过程。谢谢! - donturner
2
类似的精神:for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.label,但我更喜欢你的构造方法。 - jozxyqk

29

很好的问题。我知道三种解决方案:

解决方案 #1

替换默认小部件。

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

解决方案 #2

自定义默认小部件。如果您正在使用与该字段通常使用的相同小部件,则可以只需自定义该小部件,而无需实例化全新的小部件。

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

解决方案 #3

最后,如果您正在使用模型表单,则(除前两个解决方案外)可以通过设置内部Meta类的widgets属性来为字段指定自定义小部件。

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

1
我正要写一个和你的解决方案#2类似的解决方案。我想补充一下,你可以通过迭代self.fields来对所有字段应用操作,例如:for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth}) - Alberto Chiusole
@AlbertoChiusole 是的,如果这是你想做的,你可以这样做。感谢你指出了这一点。 - Dwayne Crooks
@DwayneCrooks 我建议您根据cdosborn的解决方案更新您的#3,因为它更短且更易读。 - Marian
我喜欢你的解决方案#2。 - SaeX

21

您可以使用此代码为表单中的每个TextInput字段添加占位符属性。占位符文本将从模型字段标签中获取。

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

5
大多数时候,我只希望所有占位符都等于模型中定义的字段的详细名称。 我已经添加了一个Mixin到任何我创建的表单,以轻松实现这一点。
class ProductForm(PlaceholderMixin, ModelForm):
    class Meta:
        model = Product
        fields = ('name', 'description', 'location', 'store')

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

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

4
感谢您的贡献。请问您能否添加一些解释,以帮助用户深入理解? - Leonard

2

当你只想覆盖一个小部件的占位符时,需要知道如何实例化一个小部件是不可取的。

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

0

看了你的方法后,我使用了这个方法来解决它。

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

3
请注意,Stack Overflow 上的内容必须为英文。除此之外,这似乎是一个“我也是”的帖子,而不是对上面提出的问题的回答。 - TylerH
1
我认为,“我也是”的帖子如果能添加更多细节是可以的。这种方法与其他方法有何不同?这里的技巧或基本学习是什么? - halfer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接