Author: Honza_Kral
Date: 2009-06-01 10:39:46 -0500 (Mon, 01 Jun 2009)
New Revision: 10871
Modified:
django/branches/soc2009/model-validation/django/contrib/contenttypes/generic.py
django/branches/soc2009/model-validation/django/db/models/base.py
django/branches/soc2009/model-validation/django/forms/models.py
django/branches/soc2009/model-validation/tests/regressiontests/views/views.py
Log:
[soc2009/model-validation] Split save_instance into make and save_made
had to add a magical attribute __adding on ModelForm to indicate whether
we are editting or adding a model. This will be later passed into the
model's .clean() method since it is necessary for correctly validating
uniques (see it's current use) and can also be used to define
force_insert or force_update params to model.save()
Also beginning with this commit, .instance attribute is present on ModelForm
and should be used to do any post-processing since manipulation of the
cleaned_data will not work
Modified:
django/branches/soc2009/model-validation/django/contrib/contenttypes/generic.py
===================================================================
---
django/branches/soc2009/model-validation/django/contrib/contenttypes/generic.py
2009-06-01 15:39:21 UTC (rev 10870)
+++
django/branches/soc2009/model-validation/django/contrib/contenttypes/generic.py
2009-06-01 15:39:46 UTC (rev 10871)
@@ -296,7 +296,11 @@
def __init__(self, data=None, files=None, instance=None, save_as_new=None,
prefix=None):
opts = self.model._meta
- self.instance = instance
+ if instance is None:
+ self.instance = self.model()
+ else:
+ self.instance = instance
+ self.save_as_new = save_as_new
self.rel_name = '-'.join((
opts.app_label, opts.object_name.lower(),
self.ct_field.name, self.ct_fk_field.name,
@@ -324,16 +328,21 @@
self.ct_fk_field.name: self.instance.pk,
})
- def save_new(self, form, commit=True):
+ def _construct_form(self, i, **kwargs):
# Avoid a circular import.
from django.contrib.contenttypes.models import ContentType
- kwargs = {
- self.ct_field.get_attname():
ContentType.objects.get_for_model(self.instance).pk,
- self.ct_fk_field.get_attname(): self.instance.pk,
- }
- new_obj = self.model(**kwargs)
- return save_instance(form, new_obj, commit=commit)
+ form = super(BaseGenericInlineFormSet, self)._construct_form(i,
**kwargs)
+ if self.save_as_new:
+ # Remove the key from the form's data, we are only
+ # creating new instances
+ form.data[form.add_prefix(self.ct_fk_field.name)] = None
+ form.data[form.add_prefix(self.ct_field.name)] = None
+ # set the GenericFK value here so that the form can do it's validation
+ setattr(form.instance, self.ct_fk_field.attname, self.instance.pk)
+ setattr(form.instance, self.ct_field.attname,
ContentType.objects.get_for_model(self.instance).pk)
+ return form
+
def generic_inlineformset_factory(model, form=ModelForm,
formset=BaseGenericInlineFormSet,
ct_field="content_type",
fk_field="object_id",
Modified: django/branches/soc2009/model-validation/django/db/models/base.py
===================================================================
--- django/branches/soc2009/model-validation/django/db/models/base.py
2009-06-01 15:39:21 UTC (rev 10870)
+++ django/branches/soc2009/model-validation/django/db/models/base.py
2009-06-01 15:39:46 UTC (rev 10871)
@@ -622,7 +622,14 @@
# TODO: run this only if not errors??
self.validate()
except ValidationError, e:
- errors[NON_FIELD_ERRORS] = e.messages
+ if hasattr(e, 'message_dict'):
+ if errors:
+ for k, v in e.message_dict.items():
+ errors.set_default(k, []).extend(v)
+ else:
+ errors = e.message_dict
+ else:
+ errors[NON_FIELD_ERRORS] = e.messages
if errors:
raise ValidationError(errors)
Modified: django/branches/soc2009/model-validation/django/forms/models.py
===================================================================
--- django/branches/soc2009/model-validation/django/forms/models.py
2009-06-01 15:39:21 UTC (rev 10870)
+++ django/branches/soc2009/model-validation/django/forms/models.py
2009-06-01 15:39:46 UTC (rev 10871)
@@ -8,7 +8,7 @@
from django.utils.text import get_text_list, capfirst
from django.utils.translation import ugettext_lazy as _, ugettext
-from django.core.exceptions import ValidationError
+from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
from util import ErrorList
from forms import BaseForm, get_declared_fields, NON_FIELD_ERRORS
from fields import Field, ChoiceField, IntegerField, EMPTY_VALUES
@@ -27,20 +27,10 @@
'ModelMultipleChoiceField',
)
-
-def save_instance(form, instance, fields=None, fail_message='saved',
- commit=True, exclude=None):
- """
- Saves bound Form ``form``'s cleaned_data into model instance ``instance``.
-
- If commit=True, then the changes to ``instance`` will be saved to the
- database. Returns ``instance``.
- """
+def make_instance(form, instance, fields=None, exclude=None):
from django.db import models
opts = instance._meta
- if form.errors:
- raise ValueError("The %s could not be %s because the data didn't"
- " validate." % (opts.object_name, fail_message))
+
cleaned_data = form.cleaned_data
file_field_list = []
for f in opts.fields:
@@ -65,9 +55,16 @@
for f in file_field_list:
f.save_form_data(instance, cleaned_data[f.name])
+ return instance
+
+def save_made_instance(form, instance, fields=None, commit=True,
fail_message='saved'):
+ opts = instance._meta
+ if form.errors:
+ raise ValueError("The %s could not be %s because the data didn't"
+ " validate." % (opts.object_name, fail_message))
+
# Wrap up the saving of m2m data as a function.
def save_m2m():
- opts = instance._meta
cleaned_data = form.cleaned_data
for f in opts.many_to_many:
if fields and f.name not in fields:
@@ -84,6 +81,18 @@
form.save_m2m = save_m2m
return instance
+
+def save_instance(form, instance, fields=None, fail_message='saved',
+ commit=True, exclude=None):
+ """
+ Saves bound Form ``form``'s cleaned_data into model instance ``instance``.
+
+ If commit=True, then the changes to ``instance`` will be saved to the
+ database. Returns ``instance``.
+ """
+ instance = make_instance(form, instance, fields, exclude)
+ return save_made_instance(form, instance, fields, commit, fail_message)
+
def make_model_save(model, fields, fail_message):
"""Returns the save() method for a Form."""
def save(self, commit=True):
@@ -218,7 +227,9 @@
# if we didn't get an instance, instantiate a new one
self.instance = opts.model()
object_data = {}
+ self.__adding = True
else:
+ self.__adding = False
self.instance = instance
object_data = model_to_dict(instance, opts.fields, opts.exclude)
# if initial was provided, it should override the values from instance
@@ -228,6 +239,8 @@
error_class, label_suffix,
empty_permitted)
def clean(self):
+ opts = self._meta
+ self.instance = make_instance(self, self.instance, opts.fields,
opts.exclude)
self.validate_unique()
return self.cleaned_data
@@ -317,7 +330,7 @@
# Exclude the current object from the query if we are editing an
# instance (as opposed to creating a new one)
- if self.instance.pk is not None:
+ if not self.__adding and self.instance.pk is not None:
qs = qs.exclude(pk=self.instance.pk)
# This cute trick with extra/values is the most efficient way to
@@ -404,9 +417,9 @@
fail_message = 'created'
else:
fail_message = 'changed'
- return save_instance(self, self.instance, self._meta.fields,
- fail_message, commit, exclude=self._meta.exclude)
+ return save_made_instance(self, self.instance, self._meta.fields,
commit, fail_message)
+
save.alters_data = True
class ModelForm(BaseModelForm):
@@ -731,6 +744,9 @@
# Remove the foreign key from the form's data
form.data[form.add_prefix(self.fk.name)] = None
+
+ # set the FK value here so that the form can do it's validation
+ setattr(form.instance, self.fk.get_attname(), self.instance.pk)
return form
#...@classmethod
Modified:
django/branches/soc2009/model-validation/tests/regressiontests/views/views.py
===================================================================
---
django/branches/soc2009/model-validation/tests/regressiontests/views/views.py
2009-06-01 15:39:21 UTC (rev 10870)
+++
django/branches/soc2009/model-validation/tests/regressiontests/views/views.py
2009-06-01 15:39:46 UTC (rev 10871)
@@ -24,7 +24,7 @@
model = Article
def save(self, *args, **kwargs):
- self.cleaned_data['slug'] = 'some-other-slug'
+ self.instance.slug = 'some-other-slug'
return super(SlugChangingArticleForm, self).save(*args, **kwargs)
return create_object(request,
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---