Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added support for specifying initial values to model formsets and inl…

…ine formsets.

This make them consistent with the similar capability of regular
formsets. Thanks to simon29 form the report and to Claude Paroz for the
patch.

Fixes #14574.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17373 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e308cfc0e155f51f14c8eb4e678c15c5f632ae30 1 parent 4e29b70
Ramiro Morales authored January 15, 2012
2  django/forms/formsets.py
@@ -122,7 +122,7 @@ def _construct_form(self, i, **kwargs):
122 122
         if self.is_bound:
123 123
             defaults['data'] = self.data
124 124
             defaults['files'] = self.files
125  
-        if self.initial:
  125
+        if self.initial and not 'initial' in kwargs:
126 126
             try:
127 127
                 defaults['initial'] = self.initial[i]
128 128
             except IndexError:
11  django/forms/models.py
@@ -418,6 +418,7 @@ class BaseModelFormSet(BaseFormSet):
418 418
     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
419 419
                  queryset=None, **kwargs):
420 420
         self.queryset = queryset
  421
+        self.initial_extra = kwargs.pop('initial', None)
421 422
         defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix}
422 423
         defaults.update(kwargs)
423 424
         super(BaseModelFormSet, self).__init__(**defaults)
@@ -448,6 +449,12 @@ def _construct_form(self, i, **kwargs):
448 449
             kwargs['instance'] = self._existing_object(pk)
449 450
         if i < self.initial_form_count() and not kwargs.get('instance'):
450 451
             kwargs['instance'] = self.get_queryset()[i]
  452
+        if i >= self.initial_form_count() and self.initial_extra:
  453
+            # Set initial values for extra forms
  454
+            try:
  455
+                kwargs['initial'] = self.initial_extra[i-self.initial_form_count()]
  456
+            except IndexError:
  457
+                pass
451 458
         return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
452 459
 
453 460
     def get_queryset(self):
@@ -674,7 +681,7 @@ def modelformset_factory(model, form=ModelForm, formfield_callback=None,
674 681
 class BaseInlineFormSet(BaseModelFormSet):
675 682
     """A formset for child objects related to a parent."""
676 683
     def __init__(self, data=None, files=None, instance=None,
677  
-                 save_as_new=False, prefix=None, queryset=None):
  684
+                 save_as_new=False, prefix=None, queryset=None, **kwargs):
678 685
         from django.db.models.fields.related import RelatedObject
679 686
         if instance is None:
680 687
             self.instance = self.fk.rel.to()
@@ -687,7 +694,7 @@ def __init__(self, data=None, files=None, instance=None,
687 694
             queryset = self.model._default_manager
688 695
         qs = queryset.filter(**{self.fk.name: self.instance})
689 696
         super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
690  
-                                                queryset=qs)
  697
+                                                queryset=qs, **kwargs)
691 698
 
692 699
     def initial_form_count(self):
693 700
         if self.save_as_new:
6  docs/releases/1.4.txt
@@ -556,6 +556,12 @@ Django 1.4 also includes several smaller improvements worth noting:
556 556
 * The MySQL database backend can now make use of the savepoint feature
557 557
   implemented by MySQL version 5.0.3 or newer with the InnoDB storage engine.
558 558
 
  559
+* It is now possible to pass initial values to the model forms that are part of
  560
+  both model formsets and inline model formset as returned from factory
  561
+  functions ``modelformset_factory`` and ``inlineformset_factory`` respectively
  562
+  just like with regular formsets. However, initial values only apply to extra
  563
+  forms i.e. those which are not bound to an existing model instance.
  564
+
559 565
 Backwards incompatible changes in 1.4
560 566
 =====================================
561 567
 
2  docs/topics/forms/formsets.txt
@@ -53,6 +53,8 @@ Formsets can also be indexed into, which returns the corresponding form. If you
53 53
 override ``__iter__``, you will need to also override ``__getitem__`` to have
54 54
 matching behavior.
55 55
 
  56
+.. _formsets-initial-data:
  57
+
56 58
 Using initial data with a formset
57 59
 ---------------------------------
58 60
 
11  docs/topics/forms/modelforms.txt
@@ -617,6 +617,17 @@ exclude::
617 617
 
618 618
     >>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))
619 619
 
  620
+Providing initial values
  621
+------------------------
  622
+
  623
+.. versionadded:: 1.4
  624
+
  625
+As with regular formsets, it is possible to :ref:`specify initial data
  626
+<formsets-initial-data>` for forms in the formset by specifying an ``initial``
  627
+parameter when instantiating the model formset class returned by
  628
+``modelformset_factory``. However, with model formsets the initial values only
  629
+apply to extra forms, those which are not bound to an existing object instance.
  630
+
620 631
 .. _saving-objects-in-the-formset:
621 632
 
622 633
 Saving objects in the formset
19  tests/regressiontests/model_formsets_regress/tests.py
@@ -204,6 +204,17 @@ def test_save_as_new_with_new_inlines(self):
204 204
             ["<Host: matrix.de.eu.dal.net>", "<Host: tranquility.hub.dal.net>"]
205 205
             )
206 206
 
  207
+    def test_initial_data(self):
  208
+        user = User.objects.create(username="bibi", serial=1)
  209
+        UserSite.objects.create(user=user, data=7)
  210
+        FormSet = inlineformset_factory(User, UserSite, extra=2)
  211
+
  212
+        formset = FormSet(instance=user, initial=[{'data': 41}, {'data': 42}])
  213
+        self.assertEqual(formset.forms[0].initial['data'], 7)
  214
+        self.assertEqual(formset.extra_forms[0].initial['data'], 41)
  215
+        self.assertTrue(u'value="42"' in formset.extra_forms[1].as_p())
  216
+
  217
+
207 218
 class FormsetTests(TestCase):
208 219
     def test_error_class(self):
209 220
         '''
@@ -230,6 +241,14 @@ def test_error_class(self):
230 241
             self.assertTrue(isinstance(form.errors, ErrorDict))
231 242
             self.assertTrue(isinstance(form.non_field_errors(), ErrorList))
232 243
 
  244
+    def test_initial_data(self):
  245
+        User.objects.create(username="bibi", serial=1)
  246
+        Formset = modelformset_factory(User, extra=2)
  247
+        formset = Formset(initial=[{'username': u'apollo11'}, {'username': u'apollo12'}])
  248
+        self.assertEqual(formset.forms[0].initial['username'], "bibi")
  249
+        self.assertEqual(formset.extra_forms[0].initial['username'], "apollo11")
  250
+        self.assertTrue(u'value="apollo12"' in formset.extra_forms[1].as_p())
  251
+
233 252
 class CustomWidget(forms.CharField):
234 253
     pass
235 254
 

0 notes on commit e308cfc

Please sign in to comment.
Something went wrong with that request. Please try again.