1
0
mirror of https://github.com/django/django.git synced 2025-07-05 10:19:20 +00:00

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
This commit is contained in:
Malcolm Tredinnick 2008-03-11 05:36:10 +00:00
parent 619576002d
commit 3176bebffd
5 changed files with 32 additions and 50 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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
=========================

View File

@ -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

View File

@ -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()