Repository: just-work/django-admin-wizard (language: python)

Issue:
Common errors intended for the form, rather than the fields, are not displayed.
The form's template output does not include display of errors intended for the form, rather than the fields. This can be done roughly like this:

```jinja2
{% extends "admin/admin_action_wizard.html" %}

{% block field_sets %}
    {{ block.super }}
    {% if adminform.form.errors %}
        {{ adminform.form.non_field_errors }}
    {% endif %}
{% endblock %}

```


Discussion / hints:

Fix patch:
diff --git a/src/admin_wizard/templates/admin/admin_action_wizard.html b/src/admin_wizard/templates/admin/admin_action_wizard.html
index 01e3366..1ab5bcb 100644
--- a/src/admin_wizard/templates/admin/admin_action_wizard.html
+++ b/src/admin_wizard/templates/admin/admin_action_wizard.html
@@ -40,6 +40,9 @@
                 {% for fieldset in adminform %}
                     {% include "admin/includes/fieldset.html" %}
                 {% endfor %}
+                {% if adminform.form.errors %}
+                    {{ adminform.form.non_field_errors }}
+                {% endif %}
             {% endblock %}
             <input type="hidden" name="action" value="{{ action }}"/>
             <input type="hidden" name="_redirect" value="{{ redirect }}"/>
diff --git a/src/admin_wizard/templates/admin/admin_update_wizard.html b/src/admin_wizard/templates/admin/admin_update_wizard.html
index 2814925..279b881 100644
--- a/src/admin_wizard/templates/admin/admin_update_wizard.html
+++ b/src/admin_wizard/templates/admin/admin_update_wizard.html
@@ -23,9 +23,12 @@
         <form action="" method="post">
             {% csrf_token %}
             {% block field_sets %}
-            {% for fieldset in adminform %}
-              {% include "admin/includes/fieldset.html" %}
-            {% endfor %}
+                {% for fieldset in adminform %}
+                    {% include "admin/includes/fieldset.html" %}
+                {% endfor %}
+                {% if adminform.form.errors %}
+                    {{ adminform.form.non_field_errors }}
+                {% endif %}
             {% endblock %}
             {{ redirect_form }}
             <input type="hidden" name="action" value="{{ action }}"/>


Test patch:
diff --git a/tests/testproject/testapp/forms.py b/tests/testproject/testapp/forms.py
index 4f205c7..5a2f68c 100644
--- a/tests/testproject/testapp/forms.py
+++ b/tests/testproject/testapp/forms.py
@@ -1,4 +1,5 @@
 from django import forms
+from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
 
 from testproject.testapp import models
 
@@ -7,3 +8,9 @@ class RenameForm(forms.ModelForm):
     class Meta:
         model = models.MyModel
         fields = ('name',)
+
+    def clean(self):
+        cd = self.cleaned_data
+        if 'xxx' in cd['name']:
+            raise ValidationError({NON_FIELD_ERRORS: ["xxx is forbidden"]})
+        return cd
\ No newline at end of file
diff --git a/tests/testproject/testapp/tests.py b/tests/testproject/testapp/tests.py
index 3c2809d..e740b6a 100644
--- a/tests/testproject/testapp/tests.py
+++ b/tests/testproject/testapp/tests.py
@@ -41,6 +41,14 @@ def test_rename_action(self):
         self.assert_object_fields(
             self.another, name='not_changed')
 
+    def test_non_field_errors_in_action(self):
+        """ Check non field errors rendering. """
+        name = admin.UpdateAction.__name__
+
+        r = self.post_admin_action(name, self.obj, name='xxx')
+
+        self.assertIn("xxx is forbidden", r.content.decode('utf-8'))
+
     def test_rename_dialog(self):
         """ Checks action dialog form_valid handling."""
         r = cast(TemplateResponse, self.post_admin_url(
@@ -57,3 +65,9 @@ def test_rename_dialog(self):
             self.obj, name='new_name')
         self.assert_object_fields(
             self.another, name='not_changed')
+
+    def test_non_field_errors_in_dialog(self):
+        """ Check non field errors rendering. """
+        r = self.post_admin_url('rename', self.obj, name='xxx')
+
+        self.assertIn("xxx is forbidden", r.content.decode('utf-8'))