summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-03-11 05:36:10 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-03-11 05:36:10 +0000
commit3176bebffd7a7e3ba131da2d1b3f9776e159f0a8 (patch)
tree8294d46b9d27c5838e4a6d5a86dd1ef7ed9f9323
parent619576002d538094dde7293d970bc4698ecdbef5 (diff)
queryset-refactor: Reorganised Model.save() to differentiate between public and private parameters. Refs #6741.
This means subclasses can override save() without needing to worry about passing around the internal parameters (an issue for subclassable models, which would have meant every model, since you don't know when somebody will subclass your model). Slightly backwards incompatible, since it moves "raw" back to being part of the internal API (it's only needed by the serializer and was intended to be internal use only). If external code really needs this, they can call Model.save_base() and pass in raw there. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7221 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/core/serializers/base.py6
-rw-r--r--django/db/models/base.py26
-rw-r--r--docs/db-api.txt31
-rw-r--r--tests/modeltests/signals/models.py3
-rw-r--r--tests/regressiontests/serializers_regress/tests.py16
5 files changed, 32 insertions, 50 deletions
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py
index 3c7dcfa02e..50c87ff276 100644
--- a/django/core/serializers/base.py
+++ b/django/core/serializers/base.py
@@ -162,12 +162,12 @@ class DeserializedObject(object):
return "<DeserializedObject: %s>" % smart_str(self.object)
def save(self, save_m2m=True):
- # Call save on the Model baseclass directly. This bypasses any
+ # Call save on the Model baseclass directly. This bypasses any
# model-defined save. The save is also forced to be raw.
- # This ensures that the data that is deserialized is literally
+ # This ensures that the data that is deserialized is literally
# what came from the file, not post-processed by pre_save/save
# methods.
- models.Model.save(self.object, raw=True)
+ models.Model.save_base(self.object, raw=True)
if self.m2m_data and save_m2m:
for accessor_name, object_list in self.m2m_data.items():
setattr(self.object, accessor_name, object_list)
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 99c6cea862..6c2bd858d4 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -253,19 +253,34 @@ class Model(object):
raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self)
- def save(self, raw=False, cls=None):
+ def save(self):
+ """
+ Save the current instance. Override this in a subclass if you want to
+ control the saving process.
+ """
+ self.save_base()
+
+ save.alters_data = True
+
+ def save_base(self, raw=False, cls=None):
+ """
+ Does the heavy-lifting involved in saving. Subclasses shouldn't need to
+ override this method. It's separate from save() in order to hide the
+ need for overrides of save() to pass around internal-only parameters
+ ('raw' and 'cls').
+ """
if not cls:
- dispatcher.send(signal=signals.pre_save, sender=self.__class__,
- instance=self, raw=raw)
cls = self.__class__
meta = self._meta
signal = True
+ dispatcher.send(signal=signals.pre_save, sender=self.__class__,
+ instance=self, raw=raw)
else:
meta = cls._meta
signal = False
for parent, field in meta.parents.items():
- self.save(raw, parent)
+ self.save_base(raw, parent)
setattr(self, field.attname, self._get_pk_val(parent._meta))
non_pks = [f for f in meta.local_fields if not f.primary_key]
@@ -311,12 +326,9 @@ class Model(object):
transaction.commit_unless_managed()
if signal:
- # Run any post-save hooks.
dispatcher.send(signal=signals.post_save, sender=self.__class__,
instance=self, created=(not record_exists), raw=raw)
- save.alters_data = True
-
def validate(self):
"""
First coerces all fields on this instance to their proper Python types.
diff --git a/docs/db-api.txt b/docs/db-api.txt
index 3cab6574ea..e626d1da86 100644
--- a/docs/db-api.txt
+++ b/docs/db-api.txt
@@ -160,37 +160,6 @@ When you save an object, Django performs the following steps:
is used to provide notification that an object has been successfully
saved. (These signals are not yet documented.)
-Raw saves
-~~~~~~~~~
-
-**New in Django development version**
-
-The pre-processing step (#2 in the previous section) is useful, but it modifies
-the data stored in a field. This can cause problems if you're relying upon the
-data you provide being used as-is.
-
-For example, if you're setting up conditions for a test, you'll want the test
-conditions to be repeatable. If pre-processing is performed, the data used
-to specify test conditions may be modified, changing the conditions for the
-test each time the test is run.
-
-In cases such as this, you need to prevent pre-processing from being performed
-when you save an object. To do this, you can invoke a **raw save** by passing
-``raw=True`` as an argument to the ``save()`` method::
-
- b4.save(raw=True) # Save object, but do no pre-processing
-
-A raw save skips the usual data pre-processing that is performed during the
-save. All other steps in the save (pre-save signal, data preparation, data
-insertion, and post-save signal) are performed as normal.
-
-.. admonition:: When to use a raw save
-
- Generally speaking, you shouldn't need to use a raw save. Disabling field
- pre-processing is an extraordinary measure that should only be required
- in extraordinary circumstances, such as setting up reliable test
- conditions.
-
Saving changes to objects
=========================
diff --git a/tests/modeltests/signals/models.py b/tests/modeltests/signals/models.py
index 5b0f5f2285..fc58d90a14 100644
--- a/tests/modeltests/signals/models.py
+++ b/tests/modeltests/signals/models.py
@@ -66,7 +66,8 @@ post_save_nokwargs signal
post_save signal, Tom Smith
Is updated
->>> p1.save(raw=True)
+# Calling an internal method purely so that we can trigger a "raw" save.
+>>> p1.save_base(raw=True)
pre_save_nokwargs signal
pre_save signal, Tom Smith
Is raw
diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py
index 24111308d7..9c42e85122 100644
--- a/tests/regressiontests/serializers_regress/tests.py
+++ b/tests/regressiontests/serializers_regress/tests.py
@@ -31,13 +31,13 @@ except ImportError:
def data_create(pk, klass, data):
instance = klass(id=pk)
instance.data = data
- models.Model.save(instance, raw=True)
+ models.Model.save_base(instance, raw=True)
return instance
def generic_create(pk, klass, data):
instance = klass(id=pk)
instance.data = data[0]
- models.Model.save(instance, raw=True)
+ models.Model.save_base(instance, raw=True)
for tag in data[1:]:
instance.tags.create(data=tag)
return instance
@@ -45,25 +45,25 @@ def generic_create(pk, klass, data):
def fk_create(pk, klass, data):
instance = klass(id=pk)
setattr(instance, 'data_id', data)
- models.Model.save(instance, raw=True)
+ models.Model.save_base(instance, raw=True)
return instance
def m2m_create(pk, klass, data):
instance = klass(id=pk)
- models.Model.save(instance, raw=True)
+ models.Model.save_base(instance, raw=True)
instance.data = data
return instance
def o2o_create(pk, klass, data):
instance = klass()
instance.data_id = data
- models.Model.save(instance, raw=True)
+ models.Model.save_base(instance, raw=True)
return instance
def pk_create(pk, klass, data):
instance = klass()
instance.data = data
- models.Model.save(instance, raw=True)
+ models.Model.save_base(instance, raw=True)
return instance
# A set of functions that can be used to compare
@@ -309,7 +309,7 @@ def fieldsTest(format, self):
management.call_command('flush', verbosity=0, interactive=False)
obj = ComplexModel(field1='first',field2='second',field3='third')
- obj.save(raw=True)
+ obj.save()
# Serialize then deserialize the test database
serialized_data = serializers.serialize(format, [obj], indent=2, fields=('field1','field3'))
@@ -325,7 +325,7 @@ def streamTest(format, self):
management.call_command('flush', verbosity=0, interactive=False)
obj = ComplexModel(field1='first',field2='second',field3='third')
- obj.save(raw=True)
+ obj.save()
# Serialize the test database to a stream
stream = StringIO()