我正在使用Twitter Bootstrap与Django一起渲染表单。
Bootstrap
可以很好地格式化你的表单-只要你有CSS
类它期望包含。
然而,我的问题是,由Django的{{ form.as_p }}
生成的表单不能很好地渲染与Bootstrap,因为他们没有这些类。
<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>
然而,在Django中为每个表单字段添加自定义CSS标签是相当痛苦的:
添加类到Django label_tag()输出
有没有一种更聪明的方法来使用{{ form.as_p }}
,或者遍历字段,而不必手动指定东西,或者做一大堆的黑客行为?
欢呼,维克多
我是这么想的:
<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>
我喜欢使用"django-crisp -forms",它是django- uniform -form的继承者。这是一个很棒的小API,对Bootstrap有很好的支持。
我倾向于使用模板过滤器来快速移植旧代码和快速表单,当我需要更多地控制呈现时使用模板标记。
当不能使用django-crispy-forms
时(例如,当模板单独处理表单的每个字段时),jcmrgo的答案是唯一的方法。根据他的回答,这里是引导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
。
你可以这样做:
{% 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 %}
为了给Django生成的表单添加CSS属性,在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">
我强烈推荐https://github.com/dyve/django-bootstrap-toolkit
这是我使用django_tweak的版本,效果更好。我发现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>
例如,您可以创建一个类,以您想要的方式定义属性,并相应地调用它。
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)
Bootstrap使用<div>
s而不是<p>
s来样式表单。所以,如果你想让它看起来漂亮,你需要100%的引导方式。下面是我比较喜欢的方式:
使用django-bootstrap3 app。示例:
{% 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 »' reset='Reset Form' layout='horizontal' %}{% endbuttons %}
</form>
注意horizontal
在1)表单类属性2)bootstrap_form布局和3)按钮布局。
最快和最简单的方法是定义你自己的基类来扩展Django Form类,并重新定义它的as_p
方法以Bootstrap要求的格式输出。然后改变你的表单,从你的新表单类继承,而不是Django的。
在来回搜索文档和stackoverflow答案后,这就是我为我创建的工作。
我检查了文档中的django-crispy-forms,发现它不支持Bootstrap 5.0 +。
Forms.py
from django.contrib.auth.forms import UserCreationForm
from .models import MyModel
class RegistrationForm(UserCreationForm):
class Meta:
model = MyModel
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2')
Views.py
from .models import MyModel
from .forms import RegistrationForm
def signup(request):
if request.method == 'POST':
r_form = RegistrationForm(request.POST)
if r_form.is_valid():
r_form.save()
return redirect('home')
else:
r_form = RegistrationForm()
context = {
'form': r_form
}
return render(request, 'myapp/signup.html', context)
sign .html (for循环方法)
<form action="/signup/" method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-floating">
<input
type="{{ field.field.widget.input_type }}"
class="form-control"
id="{{ field.id_for_label }}"
name="{{field.name}}"
required
/>
<label for="{{field.id_for_label}}">{{field.label}}</label>
</div>
{% endfor %}
<div class="d-grid gap-2 d-md-block py-2">
<button class="btn btn-primary" type="submit">Sign up</button>
</div>
</form>
sign .html(手动方法)
<form action="/signup/" method="post">
{% csrf_token %}
<div class="form-floating my-1">
<input
type="email"
class="form-control"
id="{{form.email.id_for_label}}"
name="email"
required
/>
<label for="{{form.email.id_for_label}}">Email address</label>
</div>
... next div
我已经使用了这个例子,你可能需要配置css样式。
引用- https://stackoverflow.com/a/12166096/14682396
- https://stackoverflow.com/a/14647926/14682396
- 获取django模板中的字段类型
除了其他朋友说的,我建议使用'django-widget-tweak '。
答案是这样的:
{% for field in form %}
<label for="{{ field.label }}">{{ field.label }}</label>
{{ field|add_class:"form-control" }}
<span class="error-block">{{ field.errors }}</span>
{% endfor %}