13👍
I don’t see a simple way to do this.
The errors attribute of the form actually returns an ErrorDict
, a class defined in django.forms.utils
– it’s a subclass of dict
that knows to produce that ul rendering of itself as its unicode representation. But the keys are actually the field names, and that’s important to maintain for other behavior. So it provides no easy access to the field labels.
You could define a custom template tag that accepts the form to produce the rendering you prefer, since in Python code it’s easy to get the field label given the form and the field name. Or you could construct an error list by label in the view, add it to your context, and use that instead.
edit
Alternately again, you can iterate over the fields and check their individual errors, remembering to display non_field_errors
as well. Something like:
<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>
You might want to wrap non_field_errors in a list as well, depending.
9👍
I know this has already been answered but, I ran across the same scenario and found there is a simple way to use the label:
{% 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 %}
- How can I get a textarea from model+ModelForm?
- Django send_mail() works from shell but not in nginx production
- Django DecimalField generating "quantize result has too many digits for current context" error on save
- Model in sub-directory via app_label?
- Django : loaddata to update data
2👍
I solved this in a custom form class which all my forms inherit instead of django.forms.Form
. There I change the way form.errors
works by returning a custom ErrorDict
whose as_ul
method takes labels into account. Thus you don’t need to change your templates, but you need to have your forms inherit 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 ...
- Permission checks in DRF viewsets are not working right
- Make Celery use Django's test database without task_always_eager
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)
use myform.my_errors in views.
- TypeError 'x' object has no attribute '__getitem__'
- Psycopg2.errors.InsufficientPrivilege: permission denied for relation django_migrations
0👍
Just in case anyone is looking do something like this using the django.contrib.messages
framework in, for example, a 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
)
Note this is just a basic template, you’ll have to take care of non-field errors et cetera in your code in the case where form.fields[field]
doesn’t make sense.
- 'getattr(): attribute name must be string' error in admin panel for a model with an ImageField
- Django template {% trans %} pluralization
- How could one disable new account creation with django-allauth, but still allow existing users to sign in?
- ModuleNotFoundError: No module named 'django.utils.six'
- How to get rid of the #_=_ in the facebook redirect of django-social-auth?
0👍
The following approach shows verbose_name
instead of the field name.
It can be used in get_context_data()
too but personally, I prefer this way:
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
and then use it like this:
from django import forms
class FooForm(ShowVerboseNameInFormsMixin, forms.ModelForm):
class Meta:
model = Foo
fields = ['foo', 'bar', 'baz']
with a little extra code, It can show the __all__
to all
or any other intended string.
- How to create a 8 digit Unique ID in Python?
- Django makemigrations AttributeError: 'str' object has no attribute '_meta'
- How to create a Django superuser if it doesn't exist non-interactively?
-1👍
Here’s the filter I used to render an error list with the field label, following Peter’s suggestion.
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
- How to insert a row of data to a table using Django's ORM
- Push notifications in a local network
- Django-allauth retrieve avatar profile pictures
- Django AWS S3 using Boto with Compressor fails to compress UncompressableFileError
- How to truncate/slice strings on Django Template Engine?