Django表单和Bootstrap-CSS类和<divs>


70

我正在使用Twitter BootstrapDjango与结合来渲染表单。

Bootstrap 可以很好地格式化表格-只要您有 CSS期望包含类即可。

但是,我的问题是Django生成的表单 {{ form.as_p }}在Bootstrap中表现不佳,因为它们没有这些类。

例如,Django的输出:

    <form class="horizontal-form" action="/contact/" method="post">
        <div style='display:none'>
            <input type='hidden' name='csrfmiddlewaretoken' 
                   value='26c39ab41e38cf6061367750ea8c2ea8'/>
        </div>
        <p><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" value="FOOBAR" maxlength="20" /></p>
        <p><label for="id_directory">Directory:</label> <input id="id_directory" type="text" name="directory" value="FOOBAR" maxlength="60" /></p>
       <p><label for="id_comment">Comment:</label> <textarea id="id_comment" rows="10" cols="40" name="comment">Lorem ipsum dolor sic amet.</textarea></p>
       <p>
           <label for="id_server">Server:</label>
           <select name="server" id="id_server">
               <option value="">---------</option>
               <option value="1" 
                   selected="selected">sydeqexcd01.au.db.com</option>
               <option value="2">server1</option>
               <option value="3">server2</option>
               <option value="4">server3</option>
           </select>
       </p>
       <input type="submit" value="Submit" />
    </form>

据我所知,Bootstrap要求您的表单具有<fieldset class="control-group">,每个<label>具有class="control-label",并且每个<input>包装在<div>

<fieldset class="control-group">
    <label class="control-label" for="input01">Text input</label>
    <div class="controls">
        <input type="text" class="xlarge" name="input01">
        <p class="help-text">Help text here. Be sure to fill this out like so, or else!</p>
    </div>
</fieldset>

但是,将自定义CSS标签添加到Django中的每个表单字段都非常麻烦:

将类添加到Django label_tag()输出

是否有一种更聪明的方式来使用{{ form.as_p }}或遍历这些字段,而不必手动指定事物,或者进行大量的黑客攻击?

干杯,维克多


2
您可以签出django-bootstrap-form和/或django-bootstrap。让我们知道您最终使用的是哪个,为什么!
贡巴2011年

1
django-bootstrap-form目前在功能上似乎很轻。django-bootstrap非常有前途,据我所知,它对django使用了正确的方法。这绝对是值得的。
bogeymin 2012年

Answers:


49

我喜欢使用“ django-crispy-forms”,它是django-uni-form的后继版本。这是一个很棒的小API,并且对Bootstrap有很好的支持。

当我需要对渲染进行更多控制时,我倾向于使用模板过滤器来快速移植旧代码和快速表单以及模板标签。


4
我认为这是2014
Nathan Gould

5
我刚刚检查了django-crispy-forms github页面,它看起来很活跃。因此,这可能是一个不错的选择。(不过,我对此还不是最新的内容。)
内森·古尔德

1
我不喜欢布局在django-crispy-forms中的python代码中的事实。
2016年

2
回购在2017
Anupam

55

这是我想出的:

<form class="form-horizontal" method="post">{% csrf_token %}
    <fieldset>
        <legend>{{ title }}</legend>
        {% for field in form %}
            {% if field.errors %}
                <div class="control-group error">
                    <label class="control-label">{{ field.label }}</label> 
                    <div class="controls">{{ field }}
                        <span class="help-inline">
                            {% for error in  field.errors %}{{ error }}{% endfor %}
                        </span>
                    </div>
                </div>
            {% else %}
                <div class="control-group">
                    <label class="control-label">{{ field.label }}</label> 
                    <div class="controls">{{ field }}
                        {% if field.help_text %}
                            <p class="help-inline"><small>{{ field.help_text }}</small></p>
                        {% endif %}
                    </div>
                </div>
            {% endif %}
        {% endfor %}
    </fieldset>
    <div class="form-actions">
        <button type="submit" class="btn btn-primary" >Submit</button>
    </div>
</form>

2
太棒了!谢谢。我希望最终也能够使标签成为连接到文本框侧面的跨度。我想我需要安装其他软件包来进行管理。
Karl Henselin

1
而且,如果您需要在多个模板中使用此模板,请使用可重复使用的表单模板
凤凰城

太棒了,非常有用!
mfnx

43

django-crispy-forms无法使用时(例如,当模板分别处理表单的每个字段时),jcmrgo的答案是唯一的解决方法。根据他的回答,这是Bootstrap 3(将其版本保留为Boostrap 2)的解决方案,并在模板中调整了字段类。虽然无法使用Django的标准库从模板内访问字段类(这会导致其他解决方案中出现额外的表单或模板标签),但以下解决方案可为字段标签设置正确的类,而无需在模板外部进行编码:

{% load i18n widget_tweaks %}

<form class="form-horizontal" role="form" action="." method="post">
    {% csrf_token %}
    {% for field in form %}
        {% if field.errors %}
            <div class="form-group has-error">
                <label class="col-sm-2 control-label" for="id_{{ field.name }}">{{ field.label }}</label>
                <div class="col-sm-10">
                    {{ field|attr:"class:form-control" }}
                    <span class="help-block">
                        {% for error in  field.errors %}{{ error }}{% endfor %}
                    </span>
                </div>
            </div>
        {% else %}
            <div class="form-group">
                <label class="col-sm-2 control-label" for="id_{{ field.name }}">{{ field.label }}</label>
                <div class="col-sm-10">
                    {{ field|attr:"class:form-control" }}
                    {% if field.help_text %}
                        <p class="help-block"><small>{{ field.help_text }}</small></p>
                    {% endif %}
                </div>
            </div>
        {% endif %}
    {% endfor %}
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
        </div>
    </div>
</form>

这需要django-widget-tweaks安装并widget_tweaks添加到中INSTALLED_APPS


5
截至2015年,这是最佳答案。尤其是如果您急于(需要交付)并且没有时间/没有时间去学习又一个库,例如酥脆的表格。非常感谢先生!
Asotos

2
截至2016年,这仍然是轻松集成而不需要学习清晰的最佳答案。
James Mertz

这确实应该是默认答案。django-crispy-forms如果您不想为表单创建模板并且不想花大量时间来学习大型图书馆,那是很好的选择。但是,在原始问题和实施时间的名义下;这是最好的答案。
Routhinator '16

要设置占位符(如果在表单中定义了一个占位符),则可以另外进行设置placeholder="{{ field.field.widget.attrs.placeholder }}。Django也可以id自己提供所需id="{{ field.id_for_label }}"的名称:和name="{{ field.html_name }}
–rwx

2
截至2018年,这仍然是最佳答案。我喜欢这样,它可以将演示文稿内容保留在模板中,而不是易碎的表单,这迫使我将其放入python代码中。而且,我喜欢它的启动和运行非常简单。我唯一的建议是使用“渲染字段”而不是过滤器,这在下面的另一个答案中有更详细的描述。
Deven

11

您可以执行以下操作:

{% for field in form %}
<fieldset class="control-group">
    <label class="control-label" for="id_{{ field.name }}">{{ field.label }}</label>
    <div class="controls">
        {{ field }}
        <p class="help-text">{{ field.help_text }} </p>
    </div>
</fieldset>
{% endfor %}

另请参见:form.hidden_​​fields和form.visible_fields
德怀特·甘宁

8

为了将CSS属性添加到Django生成的表单中,在forms.py中使用以下代码就足够了:

Recepient = forms.ChoiceField(label=u'Recepient', widget=forms.Select(attrs={'id':'combobox'}))

它将产生以下HTML代码:

<label for="id_Recepient">Recepient</label>
<select id="combobox" name="Recepient">


4

这是我使用django_tweaks的版本,效果更好。我发现render_field比添加过滤器更轻巧。我还添加了引导程序格式化的警报消息,并关闭了导航器验证(带有novalidate)。我是Django的新手,所以如果您发现任何废话,请立即发表评论

<form class="large" method="post" action="/suscript/" novalidate>
    {% csrf_token %}
    <fieldset>
        <legend>{{ title }}</legend>
        {% for field in form %}
            <div class="control-group {%if field.errors %}error{%endif%}">
                <div class="input-group controls">
                    <label class="input-group-addon control-label" id="{{field.label|safe}}">{{ field.label }}</label>
                    {% render_field field type="text" class="form-control" placeholder="" aria-describedby="field.label|safe" %}
                </div>
                    {% for error in field.errors %}
                         <div class="alert alert-danger">
                            <strong>{{ error|escape }}</strong>
                         </div>
                    {% endfor %}

                    {% if field.help_text %}
                        <p class="help-inline">{{ field.help_text|safe }}</p>
                    {% endif %}
            </div>

        {% endfor %}
    </fieldset>
    <div class="form-actions">
        <button type="submit" class="btn btn-primary" >Submit</button>
    </div>
</form>

3

例如,您可以创建一个类,以所需的方式定义属性,并相应地对其进行调用。

class ContactForm(ModelForm):
    class Meta:
      model = Contact
      created = MyDatePicker()

class Uniform(forms):
  def __init__(self, *args, **kwargs):
      attrs = kwargs.pop("attrs",{})
      attrs["class"] = "span3"
      kwargs["attrs"] = attrs
      super(Uniform, self).__init__(*args, **kwargs)

class MyDatePicker(Uniform,forms.DateInput)
  def __init__(self, *args, **kwargs):
      attrs = kwargs.pop("attrs",{})
      attrs["class"] = "datepick" 
      attrs["id"] =kwargs.get('datetag', '')
      kwargs["attrs"] = attrs
      super(MyDatePicker, self).__init__(*args, **kwargs)

3

Bootstrap样式形式使用<div>s而不是<p>s。因此,如果您希望它看起来不错,则需要使用引导方式100%恕我直言。这是我的首选方式:

使用django-bootstrap3应用程序。例:

{% load bootstrap3 %}

<form class="signup form-horizontal" id="signup_form" method="post" action="{% url 'account_signup' %}">
    {% csrf_token %}
    {% bootstrap_form form layout="horizontal" %}
    {% buttons submit='Sign Up &raquo;' reset='Reset Form' layout='horizontal' %}{% endbuttons %}
</form>

请注意horizontal1)表单类属性2)bootstrap_form布局和3)按钮布局。


1
我觉得这是最优雅的方式,也许这是很好的补充,还可以令个别领域,像这样:{% bootstrap_field form.field_name %}并有表单集等增加的能力
BartDur

2

最快,最简单的方法是定义自己的扩展Django Form类的基类,并重新定义其as_p方法以Bootstrap要求的格式输出。然后将您的表单更改为从新Form类继承,而不是从Django继承。


-1

除了其他朋友说的话,我建议您使用“ django-widget-tweaks”。

答案是这样的:

{% for field in form %}
      <label for="{{ field.label }}">{{ field.label }}</label>
      {{ field|add_class:"form-control" }}
      <span class="error-block">{{ field.errors }}</span>
{% endfor %}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.