使用标签而不是字段名称渲染表单错误

时间:2013-05-09 19:14:33

标签: python django django-forms

我想在模板中使用{{form.errors}}列出所有表单错误。这将生成一个表单字段列表和每个字段的错误的嵌套列表。但是,使用该字段的文字名称。在特定字段中生成的带有错误的html可能如下所示。

<ul class="errorlist">
    <li>
        target_date_mdcy
        <ul class="errorlist">
            <li>This field is required.</li>
        </ul>
    </li>
</ul>

我想使用错误列表功能,因为它很简单。但是,我想使用标签(比如说“目标日期”)而不是字段名称。实际上,我想不出你希望为网页用户显示字段名称的情况。有没有办法使用带有字段标签的渲染错误列表?

7 个答案:

答案 0 :(得分:9)

我没有看到一种简单的方法来做到这一点。

表单的errors属性实际上返回一个ErrorDict,一个在django.forms.utils中定义的类 - 它是dict的子类,它知道将其自身的ul渲染作为其unicode表示。但键实际上是字段名称,这对于维护其他行为很重要。因此,它无法轻松访问字段标签。

您可以定义一个自定义模板标记,它接受表单以生成您喜欢的呈现,因为在Python代码中,很容易获得给定表单和字段名称的字段标签。或者,您可以在视图中按标签构造错误列表,将其添加到您的上下文中,然后使用它。

修改的 或者,您可以迭代字段并检查其各自的错误,并记住也显示non_field_errors。类似的东西:

<ul class="errorlist">
  {% if form.non_field_errors %}
    <li>{{ form.non_field_errors }}</li>
  {% endif %}
  {% for field in form %}
    {% if field.errors %}
      <li>
        {{ field.label }}
        <ul class="errorlist">
          {% for error in field.errors %}
            <li>{{ error }}</li>
          {% endfor %}
        </ul>
      </li>
    {% endif %}
  {% endfor %}
</ul>

您可能希望将non_field_errors包装在列表中,具体取决于。

答案 1 :(得分:9)

我知道这已经得到了解答,但我遇到了同样的情况,发现有一种简单的方法可以使用标签:

{% if form.errors %}
    <ul class="user-msg error">
    {% for field in form %}
        {% for error in field.errors %}
            <li>
              {% if field != '__all__' %}
                <strong>{{ field.label }}:</strong>
              {% endif %}
              {{ error }}
            </li>
        {% endfor %}
    {% endfor %}
    </ul>
{% endif %}

答案 2 :(得分:2)

我在自定义表单类中解决了这个问题,我的所有表单都继承而不是django.forms.Form。在那里,我通过返回form.errors方法考虑标签的自定义ErrorDict来更改as_ul的工作方式。因此,您无需更改模板,但需要让表单继承CustomBaseForm

class CustomErrorDict(ErrorDict):
    def __init__(self, form, iterable=None, **kwargs):
        self.form = form
        super(CustomErrorDict, self).__init__(iterable, **kwargs)

    def as_ul(self):
        if not self:
            return u''

        def humanify(field_name):
            try:
                return self.form.fields[field_name].label or field_name
            except:
                return field_name

        # main logic is copied from the original ErrorDict:
        return mark_safe(u'<ul class="errorlist">%s</ul>'
                % ''.join([u'<li>%s%s</li>' % (humanify(k), force_unicode(v))
                    for k, v in self.items()]))

class CustomBaseForm(forms.Form):
    @property
    def errors(self):
        return CustomErrorDict(self, super(forms.Form, self).errors)

    ... rest of CustomBaseForm ...

答案 3 :(得分:2)

from django import forms

def my_clean(self):
    self.my_errors = ''
    for x in self.visible_fields():
        if x.errors:
            self.my_errors += "<p>%s: %s</p>" % (x.label, x.errors)


class SetPwdForm(forms.Form):
    pwd= forms.CharField(label='password', required=True, min_length=6)
    def clean(self):
        ...
        my_clean(self)

在视图中使用 myform.my_errors

答案 4 :(得分:0)

以防万一有人使用django.contrib.messages框架进行此类操作,例如FormView

def form_invalid(self, form):
    for field, errors in form.errors.items():
        for error in errors:
            messages.error(
                self.request,
                form.fields[field].label + ": " + error
            )

请注意,这只是一个基本模板,在form.fields[field]没有意义的情况下,您必须处理代码中的非字段错误等。

答案 5 :(得分:0)

以下方法显示 verbose_name 而不是字段名称。 它也可以在 get_context_data() 中使用,但就我个人而言,我更喜欢这种方式:

from django.core.exceptions import FieldDoesNotExist


class ShowVerboseNameInFormsMixin:

    def add_error(self, field, error):
        super(ShowVerboseNameInFormsMixin, self).add_error(field, error)
        for field, message in self._errors.copy().items():
            try:
                verbose_name = self._meta.model._meta.get_field(field).verbose_name
                del self._errors[field]
                self._errors[verbose_name] = self.error_class()
                self._errors[verbose_name].extend(message)
            except FieldDoesNotExist:
                pass

然后像这样使用它:

from django import forms


class FooForm(ShowVerboseNameInFormsMixin, forms.ModelForm):
    class Meta:
        model = Foo
        fields = ['foo', 'bar', 'baz']

用一点额外的代码,它可以显示 __all__all 或任何其他预期的字符串。

答案 6 :(得分:-1)

这是我用来根据彼得的建议用字段标签呈现错误列表的过滤器。

from django.utils.safestring import mark_safe
from django.template import Library, Context, loader
register = Library()

@register.filter
def form_error_list(form):

    result = ""    
    if form.errors:
        fields = form.fields
        error_items = []
        for error_field in form.errors:
            label = fields[error_field].label
            if not label:
                label = ' '.join([word.capitalize() for word in error_field.split('_')])
            errors = form.errors[error_field]
            error_li = ''.join(['<li>{0}</li>'.format(error) for error in errors])
            error_items.append({'label': label, 'error_li': error_li})    
        inner = ''.join(['<li>{0}<ul class="errorlist">{1}</ul></li>'.format(item['label'], item['error_li']) for item in error_items])
        result = mark_safe('<ul class="errorlist">{0}</ul>'.format(inner))

    return result