将类添加到表单字段Django ModelForm

时间:2015-04-18 10:29:01

标签: django django-forms django-templates

我正在尝试用Django ModelForm编写一个Bootstrap表单。我已经阅读了Django文档Django Documentation about Forms,所以我有这段代码:

<div class="form-group">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}</div>

{{form.subject}} 由Django呈现,例如在CharField字段模型中,作为输入标记,

<input type="text"....> etc.

我需要为每个输入添加“form-control”类,以获得Bootstrap输入外观(没有第三方包)。我找到了这个解决方案Django add class to form field。有没有办法在默认情况下为每个字段添加一个类,而不在Form类的每个属性中指定它?

class ExampleForm(forms.Form):
   name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
   email = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
   address = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
   country = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))

依旧......

提前致谢。

8 个答案:

答案 0 :(得分:29)

如果您无法使用第三方应用并希望以干燥的方式向表单中的每个字段添加一个类(例如“表单控件”),则可以在表单{{}中执行此操作。像这样的方法:

__init__()

如果出于某种原因,您可能需要在class ExampleForm(forms.Form): # Your declared form fields here ... def __init__(self, *args, **kwargs): super(ExampleForm, self).__init__(*args, **kwargs) for visible in self.visible_fields(): visible.field.widget.attrs['class'] = 'form-control' 内以声明方式添加类,也可能需要在attrs中处理现有类的检查。上面的代码没有考虑到这种情况。

值得一提:

您指定不想使用第三方软件包。但是,我会花一点时间提一下,以Bootstrap风格自动制作表单的最简单方法之一是使用django-crispy-forms,如下所示:

__init__()

答案 1 :(得分:7)

由于花了我更多的时间来解决这个问题,所以我将把结果也放在这里。

在每个字段中设置窗口小部件只是为了一次又一次地添加一个类,这违反了重复的编程规则,并导致许多不必要的行。使用引导程序表单时尤其如此。

这是我的(工作中)示例,它不仅添加了引导程序类:

forms.py

class CompanyForm(forms.Form):
    name = forms.CharField(label='Jméno')
    shortcut = forms.CharField(label='Zkratka')
    webpage = forms.URLField(label='Webové stránky')
    logo = forms.FileField(label='Logo')

templatetags / custom_tags.py

from django import template
from django.urls import reverse

register = template.Library()

@register.filter('input_type')
def input_type(ob):
    '''
    Extract form field type
    :param ob: form field
    :return: string of form field widget type
    '''
    return ob.field.widget.__class__.__name__


@register.filter(name='add_classes')
def add_classes(value, arg):
    '''
    Add provided classes to form field
    :param value: form field
    :param arg: string of classes seperated by ' '
    :return: edited field
    '''
    css_classes = value.field.widget.attrs.get('class', '')
    # check if class is set or empty and split its content to list (or init list)
    if css_classes:
        css_classes = css_classes.split(' ')
    else:
        css_classes = []
    # prepare new classes to list
    args = arg.split(' ')
    for a in args:
        if a not in css_classes:
            css_classes.append(a)
    # join back to single string
    return value.as_widget(attrs={'class': ' '.join(css_classes)})

reusable_form_fields.html(模板)

{% load custom_tags %}

{% csrf_token %}
{% for field in form %}
    <div class="form-group row">
        {% if field|input_type == 'TextInput' %}
            <div for="{{ field.label }}" class="col-sm-2 col-form-label">
                {{ field.label_tag }}
            </div>
            <div class="col-sm-10">
                {{ field|add_classes:'form-control'}}
                {% if field.help_text %}
                    <small class="form-text text-muted">{{ field.help_text }}</small>
                {% endif %}
            </div>
        {% else %}
            ...
        {% endif %}
    </div>
{% endfor %}

答案 2 :(得分:3)

您可以在forms.py中添加CSS类

subject = forms.CharField(label='subject', max_length=100 , widget=forms.TextInput(attrs={'class': "form-control"}))

答案 3 :(得分:0)

一种方法是创建基本表单类并手动更新__init__方法中的字段属性。

另一种方法是使用像这样的现有库: https://github.com/dyve/django-bootstrap3

github周围有很多这样的库。环顾四周。

答案 4 :(得分:0)

脆弱的形式是要走的路。 Bootstrap提示4.添加@Christian Abbott的答案,对于表单,bootstrap说,使用表单组和表单控件。 这就是它对我有用的方式。

我的forms.py

class BlogPostForm(forms.ModelForm):
    class Meta:
        model = models.Post
        fields = ['title', 'text', 'tags', 'author', 'slug']
    helper = FormHelper()
    helper.form_class = 'form-group'
    helper.layout = Layout(
        Field('title', css_class='form-control mt-2 mb-3'),
        Field('text', rows="3", css_class='form-control mb-3'),
        Field('author', css_class='form-control mb-3'),
        Field('tags', css_class='form-control mb-3'),
        Field('slug', css_class='form-control'),
    )

我的post_create.html

{% extends 'blog/new_blog_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">

<form method='POST' enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.media }}
    {% crispy form %}

<hr>
<input type="submit" name="Save" value="Save" class='btn btn-primary'> <a href="{% url 'home' %}" class='btn btn-danger'>Cancel</a>
</form>

</div>
{% endblock %}

注意:如果您使用CK Editor RichTextField()作为模型字段,那么该字段不会受到影响。如果有人知道,请更新此。

答案 5 :(得分:0)

我知道作者问过有关自己的Forms的Bootstrap,但是还有另一种方法可以在Django表单中包含Bootstrap类标签以进行身份​​验证,重置密码等。

如果我们以标准格式创建模板:

<form action="" method="post">
   {% csrf_token %}
   {{ form }}
</form>

然后在浏览器源代码中,我们可以看到带有标签的所有表单字段:

<form action="" method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="xxx">
    <tr><th><label for="id_old_password">Old password:</label></th><td><input type="password" name="old_password" autofocus required id="id_old_password"></td></tr>
    <tr><th><label for="id_new_password1">New password:</label></th><td><input type="password" name="new_password1" required id="id_new_password1"></td></tr>
    <tr><th><label for="id_new_password2">New password confirmation:</label></th><td><input type="password" name="new_password2" required id="id_new_password2"></td></tr>
</form>

我们模板中的变量{{ form }}现在可以替换为我们需要的以下代码和Bootstrap类:

<div class="fieldWrapper form-group" aria-required="true">
    <label for="id_old_password">Old password:</label><span class="required">*</span>
    <input type="password" **class="form-control"** name="old_password" autofocus required id="id_old_password">
</div>

也许对于重新设计内置的静态表单可能有用。

答案 6 :(得分:0)

我发现通过CSS识别元素并在其中添加样式更加容易。使用django表单,您将获得每个表单字段的唯一ID(如果您在模板中多次显示该表单,则为用户表单前缀)。

# views.py
def my_view_function(request):
    form_a = MyForm(prefix="a")
    form_b = MyForm(prefix="b")
    context = {
        "form_a": form_a,
        "form_b": form_b
    }
    return render(request, "template/file.html", context)

样式

// file.css
form input#by_id {
  width: 100%;
}

答案 7 :(得分:0)

好的已经过去了,但我遇到了同样的问题。我来到了这个解决方案:

class FormCssAttrsMixin():
    cssAttrs = {}

    def inject_css_attrs(self):
        # iterate through fields
        for field in self.fields:
            widget = self.fields[field].widget
            widgetClassName = widget.__class__.__name__

            # found widget which should be manipulated?
            if widgetClassName in self.cssAttrs.keys():
                # inject attributes
                attrs = self.cssAttrs[widgetClassName]
                for attr in attrs:
                    if attr in widget.attrs:  # attribute already existing
                        widget.attrs.update[attr] = widget[attr] + " " +    attrs[attr]  # append
                    else:  # create attribute since its not existing yet
                        widget.attrs[attr] = attrs[attr]


class MyForm(FormCssAttrsMixin, forms.Form):
    # add class attribute to all django textinputs widgets
    cssAttrs = {"TextInput": {"class": "form-control"}}

    name = forms.CharField()
    email = forms.CharField()
    address = forms.CharField()
    country = forms.CharField()

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

        self.inject_css_attrs()

使用这个 Mixin 类,您可以以通用的方式操作表单小部件的属性。只需添加一个字典作为类变量,其中包含每个小部件所需的属性和值。 通过这种方式,您可以在定义字段的同一位置添加 css 类。唯一的缺点是,您必须在某处调用“inject_css_attrs”方法,但我认为没关系。