Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

newforms-admin: Fixed #7230 -- Added a save_m2m method to BaseModelFo…

…rmSet when commit=False is passed to save. Thanks Books Travis for the original report.

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7930 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 55744e997f92f24608910eecf60509603ec87fec 1 parent a2c7bfc
Brian Rosner authored July 15, 2008
10  django/newforms/models.py
@@ -331,6 +331,12 @@ def save(self, commit=True):
331 331
         """Saves model instances for every form, adding and changing instances
332 332
         as necessary, and returns the list of instances.
333 333
         """
  334
+        if not commit:
  335
+            self.saved_forms = []
  336
+            def save_m2m():
  337
+                for form in self.saved_forms:
  338
+                    form.save_m2m()
  339
+            self.save_m2m = save_m2m
334 340
         return self.save_existing_objects(commit) + self.save_new_objects(commit)
335 341
 
336 342
     def save_existing_objects(self, commit=True):
@@ -353,6 +359,8 @@ def save_existing_objects(self, commit=True):
353 359
                 if form.changed_data:
354 360
                     self.changed_objects.append((obj, form.changed_data))
355 361
                     saved_instances.append(self.save_existing(form, obj, commit=commit))
  362
+                    if not commit:
  363
+                        self.saved_forms.append(form)
356 364
         return saved_instances
357 365
 
358 366
     def save_new_objects(self, commit=True):
@@ -365,6 +373,8 @@ def save_new_objects(self, commit=True):
365 373
             if self.can_delete and form.cleaned_data[DELETION_FIELD_NAME]:
366 374
                 continue
367 375
             self.new_objects.append(self.save_new(form, commit=commit))
  376
+            if not commit:
  377
+                self.saved_forms.append(form)
368 378
         return self.new_objects
369 379
 
370 380
     def add_fields(self, form, index):
4  docs/modelforms.txt
@@ -454,7 +454,9 @@ model instances without any database interaction::
454 454
     ...     instance.save()
455 455
 
456 456
 This gives you the ability to attach data to the instances before saving them
457  
-to the database.
  457
+to the database. If your formset contains a ``ManyToManyField`` you will also
  458
+need to make a call to ``formset.save_m2m()`` to ensure the many-to-many
  459
+relationships are saved properly.
458 460
 
459 461
 Limiting the number of objects editable
460 462
 ---------------------------------------
44  tests/modeltests/model_formsets/models.py
@@ -13,9 +13,19 @@ class Book(models.Model):
13 13
     def __unicode__(self):
14 14
         return self.title
15 15
 
  16
+class AuthorMeeting(models.Model):
  17
+    name = models.CharField(max_length=100)
  18
+    authors = models.ManyToManyField(Author)
  19
+    created = models.DateField(editable=False)
  20
+    
  21
+    def __unicode__(self):
  22
+        return self.name
  23
+
16 24
 
17 25
 __test__ = {'API_TESTS': """
18 26
 
  27
+>>> from datetime import date
  28
+
19 29
 >>> from django.newforms.models import modelformset_factory
20 30
 
21 31
 >>> qs = Author.objects.all()
@@ -162,6 +172,40 @@ def __unicode__(self):
162 172
 >>> formset.save()
163 173
 [<Author: Walt Whitman>]
164 174
 
  175
+Test the behavior of commit=False and save_m2m
  176
+
  177
+>>> meeting = AuthorMeeting.objects.create(created=date.today())
  178
+>>> meeting.authors = Author.objects.all()
  179
+
  180
+# create an Author instance to add to the meeting.
  181
+>>> new_author = Author.objects.create(name=u'John Steinbeck')
  182
+
  183
+>>> AuthorMeetingFormSet = modelformset_factory(AuthorMeeting, extra=1, can_delete=True)
  184
+>>> data = {
  185
+...     'form-TOTAL_FORMS': '2', # the number of forms rendered
  186
+...     'form-INITIAL_FORMS': '1', # the number of forms with initial data
  187
+...     'form-MAX_FORMS': '0', # the max number of forms
  188
+...     'form-0-id': '1',
  189
+...     'form-0-name': '2nd Tuesday of the Week Meeting',
  190
+...     'form-0-authors': [2, 1, 3, 4],
  191
+...     'form-1-name': '',
  192
+...     'form-1-authors': '',
  193
+...     'form-1-DELETE': '',
  194
+... }
  195
+>>> formset = AuthorMeetingFormSet(data=data, queryset=AuthorMeeting.objects.all())
  196
+>>> formset.is_valid()
  197
+True
  198
+>>> instances = formset.save(commit=False)
  199
+>>> for instance in instances:
  200
+...     instance.created = date.today()
  201
+...     instance.save()
  202
+>>> formset.save_m2m()
  203
+>>> instances[0].authors.all()
  204
+[<Author: Charles Baudelaire>, <Author: Walt Whitman>, <Author: Paul Verlaine>, <Author: John Steinbeck>]
  205
+
  206
+# delete the author we created to allow later tests to continue working.
  207
+>>> new_author.delete()
  208
+
165 209
 Test the behavior of max_num with model formsets. It should properly limit
166 210
 the queryset to reduce the amount of objects being pulled in when not being
167 211
 used.

0 notes on commit 55744e9

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