如何在Django模型表单中为字段添加class、id和placeholder属性

43

我有一个类似下面的Django模型

models.py

class Product(models.Model):
    name = models.CharField(max_length = 300)
    description = models.TextField(max_length = 2000)
    created = models.DateTimeField(auto_now_add = True)
    updated = models.DateTimeField(auto_now = True)

    def __unicode__(self):
        return self.name

forms.py

class ProductForm(ModelForm):
    class Meta:
        model = Product
        exclude = ('updated', 'created')

product_form.py(仅为示例)

 <form enctype="multipart/form-data" action="{% url 'add_a_product' %}" method="post">
         <div id="name">
           {{form.name}}
         </div> 
         <div id="description">
           {{form.description}}
         </div> 
   </form> 

实际上我想要展示/渲染以下类似的HTML输出

<input id="common_id_for_inputfields" type="text" placeholder="Name" class="input-calss_name" name="Name">

<input id="common_id_for_inputfields" type="text" placeholder="Description" class="input-calss_name" name="description">

最终怎样在上述代码中向模型表单字段添加属性(id、placeholder、class)?


请查看django.forms.Widget.attrs的文档。该功能实现在attributes template中。 - djvg
避免在不同的输入中使用相同的ID。 - Tariq Ahmed
9个回答

57

你可以执行以下操作:

#forms.py
class ProductForm(ModelForm):
    class Meta:
        model = Product
        exclude = ('updated', 'created')

    def __init__(self, *args, **kwargs):
        super(ProductForm, self).__init__(*args, **kwargs)
        self.fields['description'].widget = TextInput(attrs={
            'id': 'myCustomId',
            'class': 'myCustomClass',
            'name': 'myCustomName',
            'placeholder': 'myCustomPlaceholder'})

12
对我来说这个方法很有效,但是它删除了我选择窗口中的所有选项。我发现你可以完全跳过小部件声明,仍然可以设置其属性,方法如下:self.fields['description'].widget.attrs={ 'id': 'myCustomId', 'class': 'myCustomClass', 'name': 'myCustomName', 'placeholder': 'myCustomPlaceholder'}对我来说,这种方式更加简洁。 - bjesus
1
如果您想将Bootstrap类添加到所有表单中,而不必每次覆盖构造函数,请参见下面的答案。 - hurlbz
有没有一种方法可以将ID与名称相同? - cwhisperer

33

在 Django 中,字段 ID 应该自动生成,以覆盖其他字段:

class ProductForm(ModelForm):
    class Meta:
        model = Product
        exclude = ('updated', 'created')

    def __init__(self, *args, **kwargs):
        super(ProductForm, self).__init__(*args, **kwargs)
        self.fields['name'].widget.attrs\
            .update({
                'placeholder': 'Name',
                'class': 'input-calss_name'
            })

ID是否真的应该自动生成?你也可以覆盖ID。 - Alex Parakhnevich
你也可以覆盖id(就像我向你展示的那样,你可以覆盖任何属性),但我认为最好使用Django生成的ids,除非你无法控制它们(例如当你使用第三方js库或其他情况)。 - mariodev

27

我非常喜欢Dmitriy Sintsov的答案,但它并不起作用。这是一个可以起作用的版本:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for field in iter(self.fields):
        self.fields[field].widget.attrs.update({
            'class': 'form-control'
    })

更新

为了更好,请添加此条件。

if self.fields[field].widget.__class__.__name__ in ('AdminTextInputWidget' , 'Textarea' , 'NumberInput' , 'AdminURLFieldWidget', 'Select'): 
     self.fields[field].widget.attrs.update({ 'class': 'form-control' })

这比每次都要形成整个Widget好多了。我创建了一个扩展forms.ModelForm的BasicForm类来实现这一点。我只需扩展BasicForm而不是model form,就可以在所有表单上自动获取bootstrap类。我更进一步地将这些类附加到可能已经存在的任何自定义css类中。请参见我的答案以获取代码示例。 - hurlbz

20

您可以按照以下方式更新forms.py

class ProductForm(ModelForm):
    class Meta:
        model = Product
        exclude = ('updated', 'created')
        widgets={
                   "name":forms.TextInput(attrs={'placeholder':'Name','name':'Name','id':'common_id_for_imputfields','class':'input-class_name'}),
                   "description":forms.TextInput(attrs={'placeholder':'description','name':'description','id':'common_id_for_imputfields','class':'input-class_name'}),
                }  

7

这是优秀的mariodev答案的略微修改版,将bootstrap类添加到所有表单字段中,这样我就不必手动为每个字段重新创建表单输入小部件了(使用Python 3.x的super()函数)。

class ProductForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].widget.attrs.update({
                'class': 'form-control'
            })

3
如果使用“self.fields”而不是“self.Meta.fields”,它也能起作用。 - j4n7

3

add_class 过滤器用于向表单字段添加 CSS 类:

 {% load widget_tweaks %}     
    <form enctype="multipart/form-data" action="{% url 'add_a_product' %}" method="post">
                 <div id="name">
                   {{form.name|add_class:"input-calss_name"}}
                 </div> 
                 <div id="description">
                   {{form.description|add_class:"input-calss_name"}}
                 </div> 
           </form> 

Django-Widget-Tweaks 库


如果您不想覆盖默认表单,这是一种可行的方法!我已经在 Django 项目中使用它多年了。{% render_field field class+="form-check-input" %} - Jon

3

添加到 Derick Hayes 的答案,我创建了一个类 BasicForm,它扩展了 forms.ModelForm,并将 bootstrap 类添加到所有扩展它的表单中。

对于我的表单,我只需扩展 BasicForm 而不是 model form,就可以在所有表单上自动获取 bootstrap 类。我更进一步,在可能已经存在任何自定义 CSS 类的情况下,将这些类追加到它们上面。

class BaseModelForm(forms.ModelForm):

def __init__(self, *args, **kwargs):
    super(BaseModelForm, self).__init__(*args, **kwargs)
    # add common css classes to all widgets
    for field in iter(self.fields):
        #get current classes from Meta
        classes = self.fields[field].widget.attrs.get("class")
        if classes is not None:
            classes += " form-control"
        else:
            classes = "form-control"
        self.fields[field].widget.attrs.update({
            'class': classes
        })

2

您可以执行以下操作:

class ProductForm(ModelForm):
    name = forms.CharField(label='name ', 
            widget=forms.TextInput(attrs={'placeholder': 'name '}))

0

我知道这是一个老问题,但如果有人仍然想要将自定义类添加到所有表单字段中,则可以使用这个一行代码

class ProductForm(ModelForm):
    class Meta:
        model = Product
        exclude = ('updated', 'created')
def __init__(self, *args, **kwargs):
    super(ProductForm, self).__init__(*args, **kwargs)
    custom_attrs = {
        'class': 'form-control',
        'toggle-data': 'mydiv',
    }
    # adds our custom_attrs to each element of the form 
    [self.fields[i].widget.attrs.update(custom_attrs) for i in self.fields]

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