29

I have an inline formset for a model, which has a unique_together constraint. And so, when I input data, which doesn't fulfill this constraint, it displays:

__all__Please correct the duplicate values below.

The code, which does this is:

    {% for error in formset.errors %}
        {{ error }}<br/>
    {% endfor %}

I don't much like the __all__ at the beginning of the error and it is quite clearly the dictionary key, so I tried:

    {% for key, error in formset.errors %}
        {{ key }}: {{ error }}<br/>
    {% endfor %}

But then all I get is:

__all__:

{{ error }} won't display at all. So what's going on here? And how do I display the error correctly?

4 Answers 4

40

I think the problem here is that formset.errors is a list of dictionaries, not a single dictionary.

From the Django docs page on formsets:

>>> formset.errors
[{}, {'pub_date': [u'This field is required.']}]

See if something like this fixes the problem: (Updated based on the askers comments)

{% for dict in formset.errors %}
    {% for error in dict.values %}
        {{ error }}
    {% endfor %}
{% endfor %}

If that fails, I'd try using manage.py shell, and try to reproduce your situation in the python shell... that way it will be easy to inspect the various values and figure out what you need to do.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks :) Helpful. Your way didn't work, but I've finally got it working with a small modification (errors.values instead of errors), so it now looks like this: {% for dict in formset.errors %} {% for error in dict.values %} {{ error }} {% endfor %} {% endfor %}
Glad I could help. I've updated my answer based on your comments. Seems the key issue that was messing it up before was that formset.errors is a list of dicts, not a single dict.
For current version of django, looping over errors in templates is generally not what you want. Since the OP asked at the end "... how do I display the error correctly?", I would refer to the other answers not involving the looping over errors.
15

The for loops are unnecessary, these errors should be correctly displayed with the following:

{{ formset.non_form_errors }}

2 Comments

This is a function not a property thus does not return the errors as you might have expected
I agree with @Paullo For some reason this way does not show some of the errors.
11

Here is a clarification for anyone encountering similar issues of errors not being rendered in template:

If you have and error regarding the formset as a whole, use:

{{ formset.non_form_errors }}

this basically returns errors in __all__ entry from formset.errors. It is documented as:

    """
    Returns an ErrorList of errors that aren't associated with a particular
    form -- i.e., from formset.clean(). Returns an empty ErrorList if there
    are none.
    """

However if you are rendering forms from formset and some errors are not being renderd, you are probably missing:

{% for form in formset.forms %}
    {# ... #}
    {{ form.non_field_errors }}
{% endfor %}

this returns errors in __all__ entry from form.errors. Those are, analogous to the non_form_errors, the errors that aren't associated with a particular field, but rather with the field relations. For example if you had a form with fields From and To, and you validate if From value is smaller then To value, the tag {{ form.non_field_errors }} could render the following error:

'The From value must be smaller than the To value'

1 Comment

If you'd like to set the formset.non_form_errors value yourself, use the following syntax formset._non_form_errors = "my error message" (Notice the underscore before non_form_errors)
4

Django 1.6 formsets have a new method, BaseFormSet.total_error_count. Using this in a template conditional ensures you only will output errors and markup if at least one error exists in the formset.

{% if formset.total_error_count %}
    <ul class="errorList">
    {% for dict in formset.errors %}
        {% for error in dict.values %}
        <li>{{ error }}</li>
        {% endfor %}
    {% endfor %}
    </ul>
{% endif %}

See the Django docs page for v1.6+.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.