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

问题:如何在Django的CharField上添加占位符?

以这个非常简单的形式为例:

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

做到这一点的最佳方法是什么?

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?


回答 0

查看小部件文档。基本上看起来像:

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

是的,更多的写作,但是分离允许更好地抽象更复杂的情况。

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

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.


回答 1

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

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

其他方法都很好。但是,如果您不想指定该字段(例如,对于某些动态方法),则可以使用以下方法:

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的实例。

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@address.nl'

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


回答 3

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

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

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

回答 4

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

解决方案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

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

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

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

回答 5

当您只想覆盖其占位符时,不知道如何实例化窗口小部件是不可取的。

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

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"

回答 6

大多数时候,我只是希望所有占位符都等于模型中定义的字段的详细名称

我添加了一个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})

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

回答 7

在查看了您的方法之后,我使用了这种方法来解决它。

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

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