Fixed #10672 -- Altered save_base to ensure that proxy models send a post_save signal.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10954 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2009-06-08 13:04:22 +00:00
parent 6cd37e0a1f
commit 81aedbd157
2 changed files with 46 additions and 12 deletions

View File

@ -411,29 +411,35 @@ class Model(object):
save.alters_data = True save.alters_data = True
def save_base(self, raw=False, cls=None, force_insert=False, def save_base(self, raw=False, cls=None, origin=None,
force_update=False): force_insert=False, force_update=False):
""" """
Does the heavy-lifting involved in saving. Subclasses shouldn't need to 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 override this method. It's separate from save() in order to hide the
need for overrides of save() to pass around internal-only parameters need for overrides of save() to pass around internal-only parameters
('raw' and 'cls'). ('raw', 'cls', and 'origin').
""" """
assert not (force_insert and force_update) assert not (force_insert and force_update)
if not cls: if cls is None:
cls = self.__class__ cls = self.__class__
meta = self._meta meta = cls._meta
signal = True if not meta.proxy:
signals.pre_save.send(sender=self.__class__, instance=self, raw=raw) origin = cls
else: else:
meta = cls._meta meta = cls._meta
signal = False
if origin:
signals.pre_save.send(sender=origin, instance=self, raw=raw)
# If we are in a raw save, save the object exactly as presented. # If we are in a raw save, save the object exactly as presented.
# That means that we don't try to be smart about saving attributes # That means that we don't try to be smart about saving attributes
# that might have come from the parent class - we just save the # that might have come from the parent class - we just save the
# attributes we have been given to the class we have been given. # attributes we have been given to the class we have been given.
if not raw: if not raw:
if meta.proxy:
org = cls
else:
org = None
for parent, field in meta.parents.items(): for parent, field in meta.parents.items():
# At this point, parent's primary key field may be unknown # At this point, parent's primary key field may be unknown
# (for example, from administration form which doesn't fill # (for example, from administration form which doesn't fill
@ -441,7 +447,8 @@ class Model(object):
if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None: if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
self.save_base(cls=parent) self.save_base(cls=parent, origin=org)
if field: if field:
setattr(self, field.attname, self._get_pk_val(parent._meta)) setattr(self, field.attname, self._get_pk_val(parent._meta))
if meta.proxy: if meta.proxy:
@ -492,8 +499,8 @@ class Model(object):
setattr(self, meta.pk.attname, result) setattr(self, meta.pk.attname, result)
transaction.commit_unless_managed() transaction.commit_unless_managed()
if signal: if origin:
signals.post_save.send(sender=self.__class__, instance=self, signals.post_save.send(sender=origin, instance=self,
created=(not record_exists), raw=raw) created=(not record_exists), raw=raw)
save_base.alters_data = True save_base.alters_data = True

View File

@ -259,6 +259,33 @@ FieldError: Proxy model 'NoNewFields' contains model fields.
>>> OtherPerson._default_manager.all() >>> OtherPerson._default_manager.all()
[<OtherPerson: barney>, <OtherPerson: wilma>] [<OtherPerson: barney>, <OtherPerson: wilma>]
# Test save signals for proxy models
>>> from django.db.models import signals
>>> def make_handler(model, event):
... def _handler(*args, **kwargs):
... print u"%s %s save" % (model, event)
... return _handler
>>> h1 = make_handler('MyPerson', 'pre')
>>> h2 = make_handler('MyPerson', 'post')
>>> h3 = make_handler('Person', 'pre')
>>> h4 = make_handler('Person', 'post')
>>> signals.pre_save.connect(h1, sender=MyPerson)
>>> signals.post_save.connect(h2, sender=MyPerson)
>>> signals.pre_save.connect(h3, sender=Person)
>>> signals.post_save.connect(h4, sender=Person)
>>> dino = MyPerson.objects.create(name=u"dino")
MyPerson pre save
MyPerson post save
# Test save signals for proxy proxy models
>>> h5 = make_handler('MyPersonProxy', 'pre')
>>> h6 = make_handler('MyPersonProxy', 'post')
>>> signals.pre_save.connect(h5, sender=MyPersonProxy)
>>> signals.post_save.connect(h6, sender=MyPersonProxy)
>>> dino = MyPersonProxy.objects.create(name=u"pebbles")
MyPersonProxy pre save
MyPersonProxy post save
# A proxy has the same content type as the model it is proxying for (at the # A proxy has the same content type as the model it is proxying for (at the
# storage level, it is meant to be essentially indistinguishable). # storage level, it is meant to be essentially indistinguishable).
>>> ctype = ContentType.objects.get_for_model >>> ctype = ContentType.objects.get_for_model
@ -266,7 +293,7 @@ FieldError: Proxy model 'NoNewFields' contains model fields.
True True
>>> MyPersonProxy.objects.all() >>> MyPersonProxy.objects.all()
[<MyPersonProxy: barney>, <MyPersonProxy: fred>] [<MyPersonProxy: barney>, <MyPersonProxy: dino>, <MyPersonProxy: fred>, <MyPersonProxy: pebbles>]
>>> u = User.objects.create(name='Bruce') >>> u = User.objects.create(name='Bruce')
>>> User.objects.all() >>> User.objects.all()