Django 覆盖表单 HTML 标签模板?

Posted

技术标签:

【中文标题】Django 覆盖表单 HTML 标签模板?【英文标题】:Django override the form HTML label template? 【发布时间】:2018-01-01 12:40:53 【问题描述】:

在我的 settings.py 我已经设置了

FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

现在可以在中添加我自己的模板:

<project>/templates/django/forms/widgets/

<app>/templates/django/forms/widgets/

这很好用!但是,我找不到的是在哪里覆盖默认的 html(表单)标签?

class TestForm(forms.Form):
    first_name = forms.CharField(label="First name", max_length=50)
    last_name = forms.CharField(label="Last name")
    nick_name = forms.CharField(required=False)

上面的表单会像这样渲染标签:

<label for="id_first_name">First name:</label>

我想以不同的方式呈现标签。所以,我认为添加 html 标签模板会很容易:templates/django/forms/widgets/label.html

不起作用。正在浏览 Django 文档,但我找不到如何为标签执行此操作。显然标签不是小部件。

https://docs.djangoproject.com/en/1.11/ref/forms/widgets/#built-in-widgets

我的问题,我在哪里/如何更改默认标签?

【问题讨论】:

当它只是你想要设置样式的标签时,你可以进入 CSS 并写 labelwidth:200px;... 当你想要正确设置表单样式时,我建议使用 Widget-Tweaks。它是 Django 表单最个性化的样式选项,因为您可以在每个表单属性上使用纯 css。看我的回答here @hansTheFranz 谢谢。但我不是在造型之后,我想重写标签。例如,不是 您是正确的,标签不是小部件。 【参考方案1】:

这是一个可行的解决方案(在 Django 3.1 上测试):

创建 Django 表单的子类,并将 LABEL_TEMPLATE 设置为您想要的模板。

myapp/base_form.py

from django import forms
from django.forms.utils import flatatt
from django.utils.html import conditional_escape, format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _

LABEL_TEMPLATE = '<p></p>'


class CustomLabelBoundField(forms.boundfield.BoundField):


    def label_tag(self, contents=None, attrs=None, label_suffix=None):
        """
        Wrap the given contents in a <label>, if the field has an ID attribute.
        contents should be mark_safe'd to avoid HTML escaping. If contents
        aren't given, use the field's HTML-escaped label.

        If attrs are given, use them as HTML attributes on the <label> tag.

        label_suffix overrides the form's label_suffix.
        """
        contents = contents or self.label
        if label_suffix is None:
            label_suffix = (self.field.label_suffix if self.field.label_suffix is not None
                            else self.form.label_suffix)
        # Only add the suffix if the label does not end in punctuation.
        # Translators: If found as last label character, these punctuation
        # characters will prevent the default label_suffix to be appended to the label
        if label_suffix and contents and contents[-1] not in _(':?.!'):
            contents = format_html('', contents, label_suffix)
        widget = self.field.widget
        id_ = widget.attrs.get('id') or self.auto_id
        if id_:
            id_for_label = widget.id_for_label(id_)
            if id_for_label:
                attrs = **(attrs or ), 'for': id_for_label
            if self.field.required and hasattr(self.form, 'required_css_class'):
                attrs = attrs or 
                if 'class' in attrs:
                    attrs['class'] += ' ' + self.form.required_css_class
                else:
                    attrs['class'] = self.form.required_css_class
            attrs = flatatt(attrs) if attrs else ''
            contents = format_html(LABEL_TEMPLATE, attrs, contents)
        else:
            contents = conditional_escape(contents)
        return mark_safe(contents)




def get_bound_field(field, form, field_name):
    """
    Return a BoundField instance that will be used when accessing the form
    field in a template.
    """
    return CustomLabelBoundField(form, field, field_name)


class CustomLabelForm(forms.Form):

    def __getitem__(self, name):
        """Return a BoundField with the given name."""
        try:
            field = self.fields[name]
        except KeyError:
            raise KeyError(
                "Key '%s' not found in '%s'. Choices are: %s." % (
                    name,
                    self.__class__.__name__,
                    ', '.join(sorted(self.fields)),
                )
            )
        if name not in self._bound_fields_cache:
            self._bound_fields_cache[name] = get_bound_field(field, self, name)
        return self._bound_fields_cache[name]

并从CustomLabelForm 继承您的表单:

myapp/forms.py

from django import forms
from myapp.base_form import CustomLabelForm

class TestForm(CustomLabelForm):
    first_name = forms.CharField(label="First name", max_length=50)
    last_name = forms.CharField(label="Last name")
    nick_name = forms.CharField(required=False)


这会产生&lt;p for="id_first_name"&gt;First name:&lt;/p&gt;

【讨论】:

【参考方案2】:

您可以覆盖表单的__init__() 方法:

def __init__(self, *args, **kwargs):
    self.fields['field_name'].label = 'Your new label here'

【讨论】:

【参考方案3】:

实际上可以在 Django 中覆盖现有的表单小部件。

首先您需要将'django.forms' 添加到您的INSTALLED_APPS 以将其视为应用程序。

INSTALLED_APPS = [
    ...
    "django.forms",
    ...
]

然后将FORM_RENDERER 附加到您的settings.py

FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

有关TemplatesSetting 的更多信息可以在 Django 文档中找到。

之后,将您想要覆盖的任何小部件文件从django/forms/widgets/ 文件夹复制到您自己的projectname/templates/django/forms/widgets 文件夹中。自定义吧!

我希望这会有所帮助。

【讨论】:

以上是关于Django 覆盖表单 HTML 标签模板?的主要内容,如果未能解决你的问题,请参考以下文章

将 Django 表单传递给模板标签

django 表单错误。得到没有任何 html 标签的错误

Django模板标签切片不适用于表单切片

处理 django 包含模板标签中的请求

使用 Form 标签在 Django 模板中获取模型的名称

Django-jQuery 和标签?