Django

Code

Ticket #4001: 4001.diff

File 4001.diff, 2.5 kB (added by russellm, 1 year ago)

Method to add deferred m2m save method to form if commit=False

  • django/newforms/models.py

    old new  
    3535        if fields and f.name not in fields: 
    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: 
    4244                continue 
    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 
    5157def make_model_save(model, fields, fail_message): 
  • tests/modeltests/model_forms/models.py

    old new  
    332332>>> new_art.categories.all() 
    333333[] 
    334334 
     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>] 
     356 
    335357Here, we define a custom Form. Because it happens to have the same fields as 
    336358the Category model, we can use save_instance() to apply its changes to an 
    337359existing Category instance.