Skip to content

Commit

Permalink
Don't explode in non_field_errors with FormSets.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rocky Meza committed Mar 2, 2015
1 parent a840355 commit 3e10e6b
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 2 deletions.
2 changes: 2 additions & 0 deletions betterforms/multiform.py
Expand Up @@ -71,6 +71,8 @@ def is_valid(self):
def non_field_errors(self):
return ErrorList(chain.from_iterable(
form.non_field_errors() for form in self.forms.values()
# FormSets don't have non_field_errors errors
if hasattr(form, 'non_field_errors')
))

def as_table(self):
Expand Down
15 changes: 15 additions & 0 deletions docs/multiform.rst
Expand Up @@ -289,6 +289,21 @@ API Reference

.. method:: non_field_errors

.. note::

:class:`FormSets <django:django.forms.formsets.BaseFormSet>` do not
provide :meth:`non_field_errors`, they provide
:meth:`non_form_errors() <django:django.forms.formsets.BaseFormSet.non_form_errors>`,
if you put a :class:`FormSet
<django:django.forms.formsets.BaseFormSet>` in your
:attr:`form_classes`, the output of :meth:`non_field_errors` **does
not** include the
:meth:`non_form_errors() <django:django.forms.formsets.BaseFormSet.non_form_errors>`,
from the formset, you will
need to call
:meth:`non_form_errors() <django:django.forms.formsets.BaseFormSet.non_form_errors>`,
yourself.

.. method:: as_table

.. method:: as_ul
Expand Down
29 changes: 28 additions & 1 deletion tests/tests/forms.py
Expand Up @@ -4,12 +4,13 @@
from django.utils.datastructures import SortedDict as OrderedDict # NOQA

from django import forms
from django.forms.models import inlineformset_factory
from django.contrib.admin import widgets as admin_widgets
from django.core.exceptions import ValidationError

from betterforms.multiform import MultiForm, MultiModelForm

from .models import User, Profile, Badge, Author
from .models import User, Profile, Badge, Author, Book, BookImage


class UserForm(forms.ModelForm):
Expand Down Expand Up @@ -100,3 +101,29 @@ class ManyToManyMultiForm(MultiModelForm):
'badge': BadgeForm,
'author': AuthorForm,
}


class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ('name',)


BookImageFormSet = inlineformset_factory(Book, BookImage, fields=('name',))


class BookMultiForm(MultiModelForm):
form_classes = {
'book': BookForm,
'error': RaisesErrorForm,
'images': BookImageFormSet,
}

def __init__(self, *args, **kwargs):
instance = kwargs.pop('instance', None)
if instance is not None:
kwargs['instance'] = {
'book': instance,
'images': instance,
}
super(BookMultiForm, self).__init__(*args, **kwargs)
5 changes: 5 additions & 0 deletions tests/tests/models.py
Expand Up @@ -24,3 +24,8 @@ class Author(models.Model):

class Book(models.Model):
name = models.CharField(max_length=255)


class BookImage(models.Model):
book = models.ForeignKey(Book, related_name='images')
name = models.CharField(max_length=255)
13 changes: 12 additions & 1 deletion tests/tests/tests.py
Expand Up @@ -15,7 +15,7 @@
from .models import User, Profile, Badge, Book
from .forms import (
UserProfileMultiForm, BadgeMultiForm, ErrorMultiForm,
MixedForm, NeedsFileField, ManyToManyMultiForm,
MixedForm, NeedsFileField, ManyToManyMultiForm, BookMultiForm,
)


Expand Down Expand Up @@ -244,3 +244,14 @@ def test_works_with_create_view_post(self):
resp = viewfn(request)
self.assertEqual(resp.status_code, 302)
self.assertEqual(Badge.objects.count(), 2)

def test_non_field_errors_with_formset(self):
form = BookMultiForm({
'book-name': '',
'images-0-name': '',
'images-TOTAL_FORMS': '3',
'images-INITIAL_FORMS': '0',
'images-MAX_NUM_FORMS': '1000',
})
# assertDoesntRaise AttributeError
self.assertEqual(form.non_field_errors().as_text(), '* It broke')

0 comments on commit 3e10e6b

Please sign in to comment.