当我定义类似于此的Django表单类时:
def class MyForm(forms.Form):
check = forms.BooleanField(required=True, label="Check this")
它扩展为HTML,如下所示:
<form action="." id="form" method=POST>
<p><label for="check">Check this:</label> <input type="checkbox" name="check" id="check" /></p>
<p><input type=submit value="Submit"></p>
</form>
我希望复选框输入元素在复选框后面有一个标签,而不是相反。有没有办法说服Django这样做?
[编辑]
感谢Jonas的回答 - 仍然,虽然它解决了我问的问题(复选框标签呈现在复选框的右侧),但它引入了一个新问题(所有窗口小部件标签都呈现在其窗口小部件的右侧。 ..)
我想避免重写_html_output(),因为它显然不是为它而设计的。我想出的设计是在Field类中实现字段html输出方法,覆盖Boolean字段的方法,并在_html_output()中使用该方法。遗憾的是,Django开发人员选择采用不同的方式,我希望尽可能在现有框架内工作。
CSS听起来像是一个不错的方法,除了我不知道足够的CSS来解决这个问题,甚至不知道我是否喜欢这种方法。此外,我更喜欢仍然类似于最终输出的标记,至少在渲染顺序中。
此外,由于为任何特定标记提供多个样式表是合理的,因此在CSS中执行此操作可能意味着必须多次为多个样式执行此操作,这几乎使CSS成为错误的答案。
[编辑]
好像我正在回答下面的问题。如果有人知道如何做到这一点,不要害羞。
答案 0 :(得分:32)
这是我提出的解决方案(Django v1.1):
{% load myfilters %}
[...]
{% for field in form %}
[...]
{% if field.field.widget|is_checkbox %}
{{ field }}{{ field.label_tag }}
{% else %}
{{ field.label_tag }}{{ field }}
{% endif %}
[...]
{% endfor %}
您需要创建一个自定义模板标记(在此示例中为“myfilters.py”文件),其中包含以下内容:
from django import template
from django.forms.fields import CheckboxInput
register = template.Library()
@register.filter(name='is_checkbox')
def is_checkbox(value):
return isinstance(value, CheckboxInput)
有关自定义模板标签的更多信息here。
编辑:本着求问者自己答案的精神:
优点:
缺点:
答案 1 :(得分:15)
我从romkyns那里得到了答案并使其更加通用
def field_type(field, ftype):
try:
t = field.field.widget.__class__.__name__
return t.lower() == ftype
except:
pass
return False
这样您可以直接使用字符串
检查窗口小部件类型{% if field|field_type:'checkboxinput' %}
<label>{{ field }} {{ field.label }}</label>
{% else %}
<label> {{ field.label }} </label> {{ field }}
{% endif %}
答案 2 :(得分:11)
所有提出的解决方案都涉及模板修改,这些修改通常在性能方面相当低效。这是一个完成工作的自定义小部件:
from django import forms
from django.forms.fields import BooleanField
from django.forms.util import flatatt
from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.translation import ugettext as _
class PrettyCheckboxWidget(forms.widgets.CheckboxInput):
def render(self, name, value, attrs=None):
final_attrs = self.build_attrs(attrs, type='checkbox', name=name)
if self.check_test(value):
final_attrs['checked'] = 'checked'
if not (value is True or value is False or value is None or value == ''):
final_attrs['value'] = force_text(value)
if 'prettycheckbox-label' in final_attrs:
label = _(final_attrs.pop('prettycheckbox-label'))
else:
label = ''
return format_html('<label for="{0}"><input{1} /> {2}</label>', attrs['id'], flatatt(final_attrs), label)
class PrettyCheckboxField(BooleanField):
widget = PrettyCheckboxWidget
def __init__(self, *args, **kwargs):
if kwargs['label']:
kwargs['widget'].attrs['prettycheckbox-label'] = kwargs['label']
kwargs['label'] = ''
super(PrettyCheckboxField, self).__init__(*args, **kwargs)
# usage in form
class MyForm(forms.Form):
my_boolean = PrettyCheckboxField(label=_('Some label'), widget=PrettyCheckboxWidget())
我在一个额外的文件中有 PrettyCheckboxWidget 和 PrettyCheckboxField ,因此可以在需要时导入它们。如果您不需要翻译,则可以删除ugettext部分。此代码适用于 Django 1.5 ,对于较低版本未经测试。
<强>优点:强>
<强>缺点:强>
答案 3 :(得分:3)
我知道用户排除了CSS,但考虑到最佳答案需要大约半小时的工作来做这么小的事情,但是知道这些细节在网站上很重要,我会选择CSS解决方案。
checkbox.css
input[type="checkbox"] {
float: left;
margin-right: 10px;
margin-top: 4px;
}
forms.py
class MyForm(forms.ModelForm):
# ...
class Media:
css = {
'all': 'checkbox.css',
}
template.html
{{ form.media }}
{{ form.as_p }}
优点:
form.as_p
)缺点:
答案 4 :(得分:2)
这就是我最终做的事情。我写了一个自定义模板stringfilter来切换标签。现在,我的模板代码如下所示:
{% load pretty_forms %}
<form action="." method="POST">
{{ form.as_p|pretty_checkbox }}
<p><input type="submit" value="Submit"></p>
</form>
与普通Django模板的唯一区别是添加了{%load%}模板标记和 pretty_checkbox 过滤器。
这是 pretty_checkbox 的功能性但难看的实现 - 这段代码没有任何错误处理,它假设Django生成的属性以非常特定的方式格式化,这将是一个糟糕的想法在你的代码中使用这样的东西:
from django import template
from django.template.defaultfilters import stringfilter
import logging
register=template.Library()
@register.filter(name='pretty_checkbox')
@stringfilter
def pretty_checkbox(value):
# Iterate over the HTML fragment, extract <label> and <input> tags, and
# switch the order of the pairs where the input type is "checkbox".
scratch = value
output = ''
try:
while True:
ls = scratch.find('<label')
if ls > -1:
le = scratch.find('</label>')
ins = scratch.find('<input')
ine = scratch.find('/>', ins)
# Check whether we're dealing with a checkbox:
if scratch[ins:ine+2].find(' type="checkbox" ')>-1:
# Switch the tags
output += scratch[:ls]
output += scratch[ins:ine+2]
output += scratch[ls:le-1]+scratch[le:le+8]
else:
output += scratch[:ine+2]
scratch = scratch[ine+2:]
else:
output += scratch
break
except:
logging.error("pretty_checkbox caught an exception")
return output
pretty_checkbox 扫描其字符串参数,找到&lt; label&gt;对和&lt;输入&gt;如果&lt; input&gt;标签,则切换它们。标签的类型是“复选框”。它还会删除标签的最后一个字符,恰好是':'字符。
优点:
缺点:
答案 5 :(得分:1)
输入和标签的顺序是通过表单的normal_row参数提供的,并且复选框没有不同的行模式。所以有两种方法可以做到这一点(确切地说是0.96版本):
1.覆盖形式的_html_output
2.使用CSS更改标签和复选框的位置
答案 6 :(得分:1)
更改Django admin中的复选框位置可能非常棘手,但幸运的是有一个使用自定义小部件的简单解决方案:
from django.forms.widgets import Widget, CheckboxInput, boolean_check
class RightCheckbox(Widget):
render = CheckboxInput().render
def __init__(self, attrs=None, check_test=None):
super(RightCheckbox, self).__init__(attrs)
self.check_test = boolean_check if check_test is None else check_test
当widget是CheckboxInput