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
This commit is contained in:
parent
d08112a6a7
commit
78b89ff118
|
@ -5,7 +5,7 @@ and database field objects.
|
||||||
|
|
||||||
from forms import BaseForm, DeclarativeFieldsMetaclass, SortedDictFromList
|
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):
|
def model_save(self, commit=True):
|
||||||
"""
|
"""
|
||||||
|
@ -20,13 +20,19 @@ def model_save(self, commit=True):
|
||||||
obj.save()
|
obj.save()
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def make_instance_save(opts, instance):
|
def save_instance(form, instance, commit=True):
|
||||||
"Returns the save() method for a form_for_instance Form."
|
"""
|
||||||
|
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
|
from django.db import models
|
||||||
def apply_changes(self, commit=True):
|
opts = instance.__class__._meta
|
||||||
if self.errors:
|
if form.errors:
|
||||||
raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)
|
raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)
|
||||||
clean_data = self.clean_data
|
clean_data = form.clean_data
|
||||||
for f in opts.fields + opts.many_to_many:
|
for f in opts.fields + opts.many_to_many:
|
||||||
if isinstance(f, models.AutoField):
|
if isinstance(f, models.AutoField):
|
||||||
continue
|
continue
|
||||||
|
@ -34,13 +40,18 @@ def make_instance_save(opts, instance):
|
||||||
if commit:
|
if commit:
|
||||||
instance.save()
|
instance.save()
|
||||||
return instance
|
return instance
|
||||||
return apply_changes
|
|
||||||
|
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):
|
def form_for_model(model, form=BaseForm):
|
||||||
"""
|
"""
|
||||||
Returns a Form class for the given Django model class.
|
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
|
opts = model._meta
|
||||||
field_list = []
|
field_list = []
|
||||||
|
@ -55,7 +66,7 @@ def form_for_instance(instance, form=BaseForm):
|
||||||
"""
|
"""
|
||||||
Returns a Form class for the given Django model instance.
|
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__
|
model = instance.__class__
|
||||||
opts = model._meta
|
opts = model._meta
|
||||||
|
@ -67,7 +78,7 @@ def form_for_instance(instance, form=BaseForm):
|
||||||
field_list.append((f.name, formfield))
|
field_list.append((f.name, formfield))
|
||||||
fields = SortedDictFromList(field_list)
|
fields = SortedDictFromList(field_list)
|
||||||
return type(opts.object_name + 'InstanceForm', (form,),
|
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):
|
def form_for_fields(field_list):
|
||||||
"Returns a Form class for the given list of Django database field instances."
|
"Returns a Form class for the given list of Django database field instances."
|
||||||
|
|
|
@ -15,9 +15,11 @@ database.
|
||||||
The function django.newforms.form_for_instance() takes a model instance and
|
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
|
returns a Form that is tied to the instance. This form works just like any
|
||||||
other Form, with one additional method: save(). The save()
|
other Form, with one additional method: save(). The save()
|
||||||
method updates the model instance. It saves the changes to the database if
|
method updates the model instance. It also takes a commit=True parameter.
|
||||||
save(commit=True), which is default. If you pass commit=False, then you'll
|
|
||||||
get the object without committing the changes to the database.
|
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
|
from django.db import models
|
||||||
|
@ -45,7 +47,7 @@ class Article(models.Model):
|
||||||
return self.headline
|
return self.headline
|
||||||
|
|
||||||
__test__ = {'API_TESTS': """
|
__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
|
>>> import datetime
|
||||||
|
|
||||||
>>> Category.objects.all()
|
>>> Category.objects.all()
|
||||||
|
@ -218,4 +220,20 @@ Add some categories and test the many-to-many form output.
|
||||||
<option value="3">Third test</option>
|
<option value="3">Third test</option>
|
||||||
</select></li>
|
</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>
|
||||||
"""}
|
"""}
|
||||||
|
|
Loading…
Reference in New Issue