Permalink
Browse files

Fixed #3232 -- newforms: Added save_instance(), which saves a given …

…bound form's clean_data into a given model instance with the same field names

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4300 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
adrianholovaty committed Jan 9, 2007
1 parent d08112a commit 78b89ff11841c727a4738e7cbfacfb59ad9964fb
Showing with 51 additions and 22 deletions.
  1. +29 −18 django/newforms/models.py
  2. +22 −4 tests/modeltests/model_forms/models.py
View
@@ -5,7 +5,7 @@
from forms import BaseForm, DeclarativeFieldsMetaclass, SortedDictFromList
-__all__ = ('form_for_model', 'form_for_instance', 'form_for_fields')
+__all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields')
def model_save(self, commit=True):
"""
@@ -20,27 +20,38 @@ def model_save(self, commit=True):
obj.save()
return obj
-def make_instance_save(opts, instance):
- "Returns the save() method for a form_for_instance Form."
+def save_instance(form, instance, commit=True):
+ """
+ Saves bound Form ``form``'s clean_data into model instance ``instance``.
+
+ Assumes ``form`` has a field for every non-AutoField database field in
+ ``instance``. If commit=True, then the changes to ``instance`` will be
+ saved to the database. Returns ``instance``.
+ """
from django.db import models
- def apply_changes(self, commit=True):
- if self.errors:
- raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)
- clean_data = self.clean_data
- for f in opts.fields + opts.many_to_many:
- if isinstance(f, models.AutoField):
- continue
- setattr(instance, f.attname, clean_data[f.name])
- if commit:
- instance.save()
- return instance
- return apply_changes
+ opts = instance.__class__._meta
+ if form.errors:
+ raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)
+ clean_data = form.clean_data
+ for f in opts.fields + opts.many_to_many:
+ if isinstance(f, models.AutoField):
+ continue
+ setattr(instance, f.attname, clean_data[f.name])
+ if commit:
+ instance.save()
+ return instance
+
+def make_instance_save(instance):
+ "Returns the save() method for a form_for_instance Form."
+ def save(self, commit=True):
+ return save_instance(self, instance, commit)
+ return save
def form_for_model(model, form=BaseForm):
"""
Returns a Form class for the given Django model class.
- Provide 'form' if you want to use a custom BaseForm subclass.
+ Provide ``form`` if you want to use a custom BaseForm subclass.
"""
opts = model._meta
field_list = []
@@ -55,7 +66,7 @@ def form_for_instance(instance, form=BaseForm):
"""
Returns a Form class for the given Django model instance.
- Provide 'form' if you want to use a custom BaseForm subclass.
+ Provide ``form`` if you want to use a custom BaseForm subclass.
"""
model = instance.__class__
opts = model._meta
@@ -67,7 +78,7 @@ def form_for_instance(instance, form=BaseForm):
field_list.append((f.name, formfield))
fields = SortedDictFromList(field_list)
return type(opts.object_name + 'InstanceForm', (form,),
- {'fields': fields, '_model': model, 'save': make_instance_save(opts, instance)})
+ {'fields': fields, '_model': model, 'save': make_instance_save(instance)})
def form_for_fields(field_list):
"Returns a Form class for the given list of Django database field instances."
@@ -15,9 +15,11 @@
The function django.newforms.form_for_instance() takes a model instance and
returns a Form that is tied to the instance. This form works just like any
other Form, with one additional method: save(). The save()
-method updates the model instance. It saves the changes to the database if
-save(commit=True), which is default. If you pass commit=False, then you'll
-get the object without committing the changes to the database.
+method updates the model instance. It also takes a commit=True parameter.
+
+The function django.newforms.save_instance() takes a bound form instance and a
+model instance and saves the form's clean_data into the instance. It also takes
+a commit=True parameter.
"""
from django.db import models
@@ -45,7 +47,7 @@ def __str__(self):
return self.headline
__test__ = {'API_TESTS': """
->>> from django.newforms import form_for_model, form_for_instance, BaseForm
+>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
>>> import datetime
>>> Category.objects.all()
@@ -218,4 +220,20 @@ def __str__(self):
<option value="3">Third test</option>
</select></li>
+Here, we define a custom Form. Because it happens to have the same fields as
+the Category model, we can use save_instance() to apply its changes to an
+existing Category instance.
+>>> class ShortCategory(Form):
+... name = CharField(max_length=5)
+... url = CharField(max_length=3)
+>>> cat = Category.objects.get(name='Third test')
+>>> cat
+<Category: Third test>
+>>> cat.id
+3
+>>> sc = ShortCategory({'name': 'Third', 'url': '3rd'})
+>>> save_instance(sc, cat)
+<Category: Third>
+>>> Category.objects.get(id=3)
+<Category: Third>
"""}

0 comments on commit 78b89ff

Please sign in to comment.