Skip to content

Commit

Permalink
Omitting both the formsets and exclude_formsets arguments should resu…
Browse files Browse the repository at this point in the history
…lt in no formsets, rather than all formsets
  • Loading branch information
gasman committed Mar 14, 2022
1 parent 3eba3c8 commit e4447e6
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 49 deletions.
10 changes: 8 additions & 2 deletions modelcluster/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ def __new__(cls, name, bases, attrs):
opts = new_class._meta = ClusterFormOptions(getattr(new_class, 'Meta', None))
if opts.model:
formsets = {}

for rel in get_all_child_relations(opts.model):
# to build a childformset class from this relation, we need to specify:
# - the base model (opts.model)
Expand All @@ -274,9 +275,14 @@ def __new__(cls, name, bases, attrs):
rel_name = rel.get_accessor_name()

# apply 'formsets' and 'exclude_formsets' rules from meta
if opts.formsets is not None and rel_name not in opts.formsets:
if opts.exclude_formsets is not None and rel_name in opts.exclude_formsets:
# formset is explicitly excluded
continue
elif opts.formsets is not None and rel_name not in opts.formsets:
# a formset list has been specified and this isn't on it
continue
if opts.exclude_formsets and rel_name in opts.exclude_formsets:
elif opts.formsets is None and opts.exclude_formsets is None:
# neither formsets nor exclude_formsets has been specified - no formsets at all
continue

try:
Expand Down
128 changes: 85 additions & 43 deletions tests/tests/test_cluster_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,27 @@


class ClusterFormTest(TestCase):
def test_cluster_form_with_no_formsets(self):
class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']

self.assertFalse(BandForm.formsets)

beatles = Band(name='The Beatles')
form = BandForm(instance=beatles)
form_html = form.as_p()
self.assertIsInstance(form_html, SafeString)
self.assertInHTML('<label for="id_name">Name:</label>', form_html)
self.assertInHTML('<label for="id_albums-0-name">Name:</label>', form_html, count=0)

def test_cluster_form(self):
class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

self.assertTrue(BandForm.formsets)

Expand All @@ -33,13 +49,15 @@ class Meta:
self.assertEqual(5, len(form.formsets['members'].forms))
form_html = form.as_p()
self.assertIsInstance(form_html, SafeString)
self.assertInHTML('<label for="id_name">Name:</label>', form_html)
self.assertInHTML('<label for="id_albums-0-name">Name:</label>', form_html)

def test_empty_cluster_form(self):
class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

form = BandForm()

Expand All @@ -50,6 +68,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

beatles = Band(name='The Beatles', members=[
BandMember(name='George Harrison'),
Expand Down Expand Up @@ -133,6 +152,7 @@ class Meta:
}
}
fields = ['name']
formsets = ['members', 'albums']

form = BandForm()
self.assertEqual(Textarea, type(form['name'].field.widget))
Expand Down Expand Up @@ -250,6 +270,7 @@ class BandFormWithFFC(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

form = BandFormWithFFC()
self.assertEqual(Textarea, type(form['name'].field.widget))
Expand All @@ -260,6 +281,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

john = BandMember(name='John Lennon')
paul = BandMember(name='Paul McCartney')
Expand Down Expand Up @@ -300,48 +322,6 @@ class Meta:
self.assertTrue(BandMember.objects.filter(name='George Harrison').exists())
self.assertFalse(BandMember.objects.filter(name='John Lennon').exists())

def test_can_omit_formset_from_submission(self):
"""
If no explicit `formsets` parameter has been given, any formsets missing from the
submission should be skipped over.
https://github.com/wagtail/wagtail/issues/5414#issuecomment-567468127
"""
class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']

john = BandMember(name='John Lennon')
paul = BandMember(name='Paul McCartney')
abbey_road = Album(name='Abbey Road')
beatles = Band(name='The Beatles', members=[john, paul], albums=[abbey_road])
beatles.save()

form = BandForm({
'name': "The Beatles",

'members-TOTAL_FORMS': 3,
'members-INITIAL_FORMS': 2,
'members-MAX_NUM_FORMS': 1000,

'members-0-name': john.name,
'members-0-DELETE': 'members-0-DELETE',
'members-0-id': john.id,

'members-1-name': paul.name,
'members-1-id': paul.id,

'members-2-name': 'George Harrison',
'members-2-id': '',
}, instance=beatles)
self.assertTrue(form.is_valid())
form.save()

beatles = Band.objects.get(id=beatles.id)
self.assertEqual(1, beatles.albums.count())
self.assertTrue(BandMember.objects.filter(name='George Harrison').exists())
self.assertFalse(BandMember.objects.filter(name='John Lennon').exists())

def test_cannot_omit_explicit_formset_from_submission(self):
"""
If an explicit `formsets` parameter has been given, formsets missing from a form submission
Expand Down Expand Up @@ -389,6 +369,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

john = BandMember(name='John Lennon')
paul = BandMember(name='Paul McCartney')
Expand Down Expand Up @@ -435,6 +416,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

form = BandForm({
'name': "The Beatles",
Expand Down Expand Up @@ -475,6 +457,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

form = BandForm()
form_html = form.as_p()
Expand All @@ -486,6 +469,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

form = BandForm({
'name': "The Beatles",
Expand Down Expand Up @@ -525,6 +509,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

please_please_me = Album(name='Please Please Me', release_date=datetime.date(1963, 3, 22))
beatles = Band(name='The Beatles', albums=[please_please_me])
Expand Down Expand Up @@ -582,7 +567,7 @@ class Meta:
beatles.save()
self.assertEqual(0, Band.objects.get(id=beatles.id).albums.count())

def test_cluster_form_without_formsets(self):
def test_cluster_form_with_empty_formsets_list(self):
class BandForm(ClusterForm):
class Meta:
model = Band
Expand All @@ -609,6 +594,7 @@ class RestaurantForm(ClusterForm):
class Meta:
model = Restaurant
fields = ['name', 'tags', 'serves_hot_dogs', 'proprietor']
formsets = ['menu_items', 'reviews', 'tagged_items']

self.assertIn('reviews', RestaurantForm.formsets)

Expand Down Expand Up @@ -678,6 +664,7 @@ class FormWithWidgetMedia(ClusterForm):
class Meta:
model = Restaurant
fields = ['name', 'tags', 'serves_hot_dogs', 'proprietor']
formsets = ['menu_items', 'reviews', 'tagged_items']
widgets = {
'name': WidgetWithMedia
}
Expand Down Expand Up @@ -760,6 +747,7 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets = ['members', 'albums']

form = BandForm({
'name': "The Beatles",
Expand Down Expand Up @@ -861,11 +849,37 @@ class Meta:

class NestedClusterFormTest(TestCase):

def test_no_nested_formsets_without_explicit_formset_definition(self):
class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets=['members', 'albums']

self.assertTrue(BandForm.formsets)

beatles = Band(name='The Beatles', albums=[
Album(name='Please Please Me', songs=[
Song(name='I Saw Her Standing There'),
Song(name='Misery')
]),
])

form = BandForm(instance=beatles)

self.assertEqual(4, len(form.formsets['albums'].forms))
self.assertNotIn('songs', form.formsets['albums'].forms[0].formsets)
self.assertNotIn('songs', form.as_p())

def test_nested_formsets(self):
class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

self.assertTrue(BandForm.formsets)

Expand All @@ -887,6 +901,10 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

form = BandForm()
self.assertEqual(3, len(form.formsets['albums'].forms))
Expand All @@ -897,6 +915,10 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

beatles = Band(name='The Beatles', albums=[
Album(name='Please Please Me', songs=[
Expand Down Expand Up @@ -987,6 +1009,10 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

first_song = Song(name='I Saw Her Standing There')
second_song = Song(name='Misery')
Expand Down Expand Up @@ -1042,6 +1068,10 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

first_song = Song(name='I Saw Her Standing There')
second_song = Song(name='Misery')
Expand Down Expand Up @@ -1095,6 +1125,10 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

form = BandForm({
'name': "The Beatles",
Expand Down Expand Up @@ -1144,6 +1178,10 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

form = BandForm()
form_html = form.as_p()
Expand All @@ -1155,6 +1193,10 @@ class BandForm(ClusterForm):
class Meta:
model = Band
fields = ['name']
formsets={
'members': [],
'albums': {'formsets': ['songs']}
}

form = BandForm({
'name': "The Beatles",
Expand Down
8 changes: 4 additions & 4 deletions tests/tests/test_formset.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ def test_can_create_formset(self):
Song(name='Misery')
])
])
AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, extra=3)
AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, formsets=['songs'], extra=3)
albums_formset = AlbumsFormset(instance=beatles)

self.assertEqual(4, len(albums_formset.forms))
Expand All @@ -480,7 +480,7 @@ def test_can_create_formset(self):
)

def test_empty_formset(self):
AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, extra=3)
AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, formsets=['songs'], extra=3)
albums_formset = AlbumsFormset()
self.assertEqual(3, len(albums_formset.forms))
self.assertEqual(3, len(albums_formset.forms[0].formsets['songs'].forms))
Expand All @@ -493,7 +493,7 @@ def test_save_commit_false(self):
beatles.save()
first_song_id, second_song_id = first_song.id, second_song.id

AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, extra=3)
AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, formsets=['songs'], extra=3)

albums_formset = AlbumsFormset({
'form-TOTAL_FORMS': 1,
Expand Down Expand Up @@ -555,7 +555,7 @@ def test_child_updates_without_ids(self):
second_song = Song(name='Misery')
album.songs.add(second_song)

AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, extra=3)
AlbumsFormset = childformset_factory(Band, Album, form=ClusterForm, formsets=['songs'], extra=3)

albums_formset = AlbumsFormset({
'form-TOTAL_FORMS': 1,
Expand Down

0 comments on commit e4447e6

Please sign in to comment.