Skip to content

Commit

Permalink
Add inherit_kwargs attribute to ClusterForm child formsets (wagtail#156)
Browse files Browse the repository at this point in the history
This specifies a list of keyword argument names; when any of these are passed to the parent ClusterForm's constructor, they will also be passed on to the child forms of that formset (via the formset's form_kwargs keyword argument).
  • Loading branch information
gasman authored Mar 4, 2022
1 parent 7e0fc1c commit ad5912e
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 2 deletions.
20 changes: 18 additions & 2 deletions modelcluster/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ def transientmodelformset_factory(model, formset=BaseTransientModelFormSet, **kw


class BaseChildFormSet(BaseTransientModelFormSet):
inherit_kwargs = None

def __init__(self, data=None, files=None, instance=None, queryset=None, **kwargs):
if instance is None:
self.instance = self.fk.remote_field.model()
Expand Down Expand Up @@ -171,7 +173,8 @@ def childformset_factory(
parent_model, model, form=ModelForm,
formset=BaseChildFormSet, fk_name=None, fields=None, exclude=None,
extra=3, can_order=False, can_delete=True, max_num=None, validate_max=False,
formfield_callback=None, widgets=None, min_num=None, validate_min=False
formfield_callback=None, widgets=None, min_num=None, validate_min=False,
inherit_kwargs=None,
):

fk = _get_foreign_key(parent_model, model, fk_name=fk_name)
Expand Down Expand Up @@ -203,6 +206,11 @@ def childformset_factory(
}
FormSet = transientmodelformset_factory(model, **kwargs)
FormSet.fk = fk

# A list of keyword argument names that should be passed on from ClusterForm's constructor
# to child forms in this formset
FormSet.inherit_kwargs = inherit_kwargs

return FormSet


Expand Down Expand Up @@ -296,7 +304,15 @@ def __init__(self, data=None, files=None, instance=None, prefix=None, **kwargs):
formset_prefix = "%s-%s" % (prefix, rel_name)
else:
formset_prefix = rel_name
self.formsets[rel_name] = formset_class(data, files, instance=instance, prefix=formset_prefix)

child_form_kwargs = {}
if formset_class.inherit_kwargs:
for kwarg_name in formset_class.inherit_kwargs:
child_form_kwargs[kwarg_name] = kwargs.get(kwarg_name)

self.formsets[rel_name] = formset_class(
data, files, instance=instance, prefix=formset_prefix, form_kwargs=child_form_kwargs
)

if self.is_bound and not self._has_explicit_formsets:
# check which formsets have actually been provided as part of the form submission -
Expand Down
40 changes: 40 additions & 0 deletions tests/tests/test_cluster_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,46 @@ class Meta:
self.assertNotIn('release_date', form.formsets['albums'].forms[0].fields)
self.assertEqual(Textarea, type(form.formsets['albums'].forms[0]['name'].field.widget))

def test_without_kwarg_inheritance(self):
# by default, kwargs passed to the ClusterForm do not propagate to child forms
class BandForm(ClusterForm):
class Meta:
model = Band
formsets = {
'members': {'fields': ['name']}
}
fields = ['name']

form = BandForm(label_suffix="!!!:")
form_html = form.as_p()
# band name field should have label_suffix applied
self.assertInHTML('<label for="id_name">Name!!!:</label>', form_html)
# but this should not propagate to member form fields
self.assertInHTML('<label for="id_members-0-name">Name!!!:</label>', form_html, count=0)

def test_with_kwarg_inheritance(self):
# inherit_kwargs should allow kwargs passed to the ClusterForm to propagate to child forms
class BandForm(ClusterForm):
class Meta:
model = Band
formsets = {
'members': {'fields': ['name'], 'inherit_kwargs': ['label_suffix']}
}
fields = ['name']

form = BandForm(label_suffix="!!!:")
form_html = form.as_p()
# band name field should have label_suffix applied
self.assertInHTML('<label for="id_name">Name!!!:</label>', form_html)
# and this should propagate to member form fields too
self.assertInHTML('<label for="id_members-0-name">Name!!!:</label>', form_html)

# the form should still work without a label_suffix kwarg
form = BandForm()
form_html = form.as_p()
self.assertInHTML('<label for="id_name">Name:</label>', form_html)
self.assertInHTML('<label for="id_members-0-name">Name:</label>', form_html)

def test_custom_formset_form(self):
class AlbumForm(ClusterForm):
pass
Expand Down

0 comments on commit ad5912e

Please sign in to comment.