Django

Code

Changeset 5804

Show
Ignore:
Timestamp:
08/05/07 02:39:36 (2 years ago)
Author:
russellm
Message:

Fixed #4001 -- Added dynamic save_m2m method() to forms created with form_for_model and form_for_instance on save(commit=False).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/newforms/models.py

    r5609 r5804  
    3636            continue 
    3737        setattr(instance, f.name, cleaned_data[f.name]) 
    38     if commit: 
    39         instance.save() 
     38    # Wrap up the saving of m2m data as a function 
     39    def save_m2m(): 
     40        opts = instance.__class__._meta 
     41        cleaned_data = form.cleaned_data 
    4042        for f in opts.many_to_many: 
    4143            if fields and f.name not in fields: 
     
    4345            if f.name in cleaned_data: 
    4446                setattr(instance, f.attname, cleaned_data[f.name]) 
    45     # GOTCHA: If many-to-many data is given and commit=False, the many-to-many 
    46     # data will be lost. This happens because a many-to-many options cannot be 
    47     # set on an object until after it's saved. Maybe we should raise an 
    48     # exception in that case. 
     47    if commit: 
     48        # If we are committing, save the instance and the m2m data immediately 
     49        instance.save() 
     50        save_m2m() 
     51    else: 
     52        # We're not committing. Add a method to the form to allow deferred  
     53        # saving of m2m data 
     54        form.save_m2m = save_m2m 
    4955    return instance 
    5056 
  • django/trunk/docs/newforms.txt

    r5803 r5804  
    15031503object before saving it. ``commit`` is ``True`` by default. 
    15041504 
     1505Another side effect of using ``commit=False`` is seen when your model has 
     1506a many-to-many relation with another model. If your model has a many-to-many 
     1507relation and you specify ``commit=False`` when you save a form, Django cannot 
     1508immediately save the form data for the many-to-many relation. This is because 
     1509it isn't possible to save many-to-many data for an instance until the instance 
     1510exists in the database. 
     1511 
     1512To work around this problem, every time you save a form using ``commit=False``, 
     1513Django adds a ``save_m2m()`` method to the form created by ``form_for_model``. 
     1514After you have manually saved the instance produced by the form, you can invoke 
     1515``save_m2m()`` to save the many-to-many form data:: 
     1516 
     1517    # Create a form instance with POST data. 
     1518    >>> f = AuthorForm(request.POST) 
     1519 
     1520    # Create, but don't save the new author instance 
     1521    >>> new_author = f.save(commit=False) 
     1522 
     1523    # Modify the author in some way 
     1524    ... 
     1525    # Save the new instance 
     1526    >>> new_author.save() 
     1527 
     1528    # Now save the many-to-many data for the form 
     1529    >>> f.save_m2m() 
     1530 
     1531Calling ``save_m2m()`` is only required if you use ``save(commit=False)``. 
     1532When you use a simple ``save()`` on a form, all data - include 
     1533many-to-many data - is saved without the need for any additional method calls. 
     1534 
    15051535Using an alternate base class 
    15061536~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  • django/trunk/tests/modeltests/model_forms/models.py

    r5803 r5804  
    332332>>> new_art.categories.all() 
    333333[] 
     334 
     335Create a new article, with categories, via the form, but use commit=False. 
     336The m2m data won't be saved until save_m2m() is invoked on the form. 
     337>>> ArticleForm = form_for_model(Article) 
     338>>> f = ArticleForm({'headline': u'The walrus was Paul', 'pub_date': u'1967-11-01', 
     339...     'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) 
     340>>> new_art = f.save(commit=False) 
     341 
     342# Manually save the instance  
     343>>> new_art.save() 
     344>>> new_art.id 
     3454 
     346 
     347# The instance doesn't have m2m data yet 
     348>>> new_art = Article.objects.get(id=4) 
     349>>> new_art.categories.all() 
     350[] 
     351 
     352# Save the m2m data on the form 
     353>>> f.save_m2m() 
     354>>> new_art.categories.all() 
     355[<Category: Entertainment>, <Category: It's a test>] 
    334356 
    335357Here, we define a custom Form. Because it happens to have the same fields as