注意:希望即将推出的 Django 4.0 将使这一切变得更容易,因为它提供了template based form rendering。
在那之前:
OP 要求一种在表单定义中使用BoundField.label_tag() 的方法。
user240515 和user2732686 的回答确实提供了一些实施建议,但没有提供任何理由。
大多数其他基于自定义模板标签的解决方案都需要我们手动渲染表单字段,因此如果我们只是想使用{{ form }},它们就不起作用。
因此,除了所有这些答案之外,这里还尝试提供更多背景信息。
关于标签标签
表单标签由BaseForm.as_table()、as_ul()或as_p()shortcuts通过“私有”BaseForm._html_output()方法呈现,如source所示。
这是通过调用BoundField.label_tag() 来完成的,如here 所示。
label_tag() 方法采用 attrs 参数以及 <label> 标记的附加 HTML 属性。
但是,问题在于BaseForm._html_output() 调用label_tag() 时没有attrs,并且没有简单的替代方法来设置attrs 参数。
如何扩展label_tag?
Django 的contrib.admin 通过在其AdminField 中扩展label_tag() 方法解决了这个问题,正如source 所清楚的那样。
要扩展BoundField.label_tag(),我们可以create a customized BoundField:
class MyBoundField(forms.BoundField):
def __init__(self, form, field, name, label_attrs=None):
super().__init__(form, field, name)
self.label_attrs = label_attrs
def label_tag(self, contents=None, attrs=None, label_suffix=None):
if attrs is None:
attrs = dict()
attrs.update(self.label_attrs or {})
return super().label_tag(contents, attrs, label_suffix)
现在我们可以创建一个带有特定标签属性的绑定字段,但是我们如何处理它呢?
如何使用自定义绑定字段?
绑定字段使用forms.Field.get_bound_field() 进行实例化,因此,我们可以重写该方法以返回我们的自定义绑定字段:
class MyField(forms.Field):
# note typically we would use any of django's forms.Field subclasses
def __init__(self, *args, **kwargs):
# we could also set label_attrs here, based on the field properties
self.label_attrs = kwargs.pop('label_attrs', None)
super().__init__(*args, **kwargs)
def get_bound_field(self, form, field_name):
return MyBoundField(
form=form, field=self, name=field_name, label_attrs=self.label_attrs)
然后我们可以使用Form上的自定义字段:
class MyForm(forms.Form):
some_field = MyField(..., label_attrs={'class': 'my-class'})
但是如果我们想对所有的表单域都这样做呢?
如何为所有表单字段使用自定义绑定字段?
最后,Field.get_bound_field() 在BaseForm.__getitem__() 中被调用(见source)。这意味着我们可以通过调用例如得到一个绑定字段。 my_form['some_field'].
为了对表单的所有字段使用我们的自定义绑定字段,我们可以为表单中的所有字段使用monkey patchfield.get_bound_field,或者我们可以覆盖表单的__getitem__()以忽略get_bound_field(),而是使用直接MyBoundField。
这是一个覆盖示例,它主要是 original source 的副本,MyBoundField 行除外:
class MyForm(forms.Form):
label_attrs = {'class': 'my-class'}
def __getitem__(self, name):
"""Return a MyBoundField with the given name."""
try:
field = self.fields[name]
except KeyError:
... # left out for clarity
if name not in self._bound_fields_cache:
self._bound_fields_cache[name] = MyBoundField(
form=self, field=field, name=name, label_attrs=self.label_attrs)
return self._bound_fields_cache[name]
最后,这一切似乎很多对于一些造型的麻烦。