Loading django/db/models/base.py +18 −11 Original line number Diff line number Diff line Loading @@ -411,29 +411,35 @@ class Model(object): save.alters_data = True def save_base(self, raw=False, cls=None, force_insert=False, force_update=False): def save_base(self, raw=False, cls=None, origin=None, force_insert=False, force_update=False): """ 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'). ('raw', 'cls', and 'origin'). """ assert not (force_insert and force_update) if not cls: if cls is None: cls = self.__class__ meta = self._meta signal = True signals.pre_save.send(sender=self.__class__, instance=self, raw=raw) meta = cls._meta if not meta.proxy: origin = cls else: 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. # 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 # attributes we have been given to the class we have been given. if not raw: if meta.proxy: org = cls else: org = None for parent, field in meta.parents.items(): # At this point, parent's primary key field may be unknown # (for example, from administration form which doesn't fill Loading @@ -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: setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) self.save_base(cls=parent) self.save_base(cls=parent, origin=org) if field: setattr(self, field.attname, self._get_pk_val(parent._meta)) if meta.proxy: Loading Loading @@ -492,8 +499,8 @@ class Model(object): setattr(self, meta.pk.attname, result) transaction.commit_unless_managed() if signal: signals.post_save.send(sender=self.__class__, instance=self, if origin: signals.post_save.send(sender=origin, instance=self, created=(not record_exists), raw=raw) save_base.alters_data = True Loading tests/modeltests/proxy_models/models.py +28 −1 Original line number Diff line number Diff line Loading @@ -259,6 +259,33 @@ FieldError: Proxy model 'NoNewFields' contains model fields. >>> OtherPerson._default_manager.all() [<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 # storage level, it is meant to be essentially indistinguishable). >>> ctype = ContentType.objects.get_for_model Loading @@ -266,7 +293,7 @@ FieldError: Proxy model 'NoNewFields' contains model fields. True >>> MyPersonProxy.objects.all() [<MyPersonProxy: barney>, <MyPersonProxy: fred>] [<MyPersonProxy: barney>, <MyPersonProxy: dino>, <MyPersonProxy: fred>, <MyPersonProxy: pebbles>] >>> u = User.objects.create(name='Bruce') >>> User.objects.all() Loading Loading
django/db/models/base.py +18 −11 Original line number Diff line number Diff line Loading @@ -411,29 +411,35 @@ class Model(object): save.alters_data = True def save_base(self, raw=False, cls=None, force_insert=False, force_update=False): def save_base(self, raw=False, cls=None, origin=None, force_insert=False, force_update=False): """ 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'). ('raw', 'cls', and 'origin'). """ assert not (force_insert and force_update) if not cls: if cls is None: cls = self.__class__ meta = self._meta signal = True signals.pre_save.send(sender=self.__class__, instance=self, raw=raw) meta = cls._meta if not meta.proxy: origin = cls else: 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. # 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 # attributes we have been given to the class we have been given. if not raw: if meta.proxy: org = cls else: org = None for parent, field in meta.parents.items(): # At this point, parent's primary key field may be unknown # (for example, from administration form which doesn't fill Loading @@ -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: setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) self.save_base(cls=parent) self.save_base(cls=parent, origin=org) if field: setattr(self, field.attname, self._get_pk_val(parent._meta)) if meta.proxy: Loading Loading @@ -492,8 +499,8 @@ class Model(object): setattr(self, meta.pk.attname, result) transaction.commit_unless_managed() if signal: signals.post_save.send(sender=self.__class__, instance=self, if origin: signals.post_save.send(sender=origin, instance=self, created=(not record_exists), raw=raw) save_base.alters_data = True Loading
tests/modeltests/proxy_models/models.py +28 −1 Original line number Diff line number Diff line Loading @@ -259,6 +259,33 @@ FieldError: Proxy model 'NoNewFields' contains model fields. >>> OtherPerson._default_manager.all() [<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 # storage level, it is meant to be essentially indistinguishable). >>> ctype = ContentType.objects.get_for_model Loading @@ -266,7 +293,7 @@ FieldError: Proxy model 'NoNewFields' contains model fields. True >>> MyPersonProxy.objects.all() [<MyPersonProxy: barney>, <MyPersonProxy: fred>] [<MyPersonProxy: barney>, <MyPersonProxy: dino>, <MyPersonProxy: fred>, <MyPersonProxy: pebbles>] >>> u = User.objects.create(name='Bruce') >>> User.objects.all() Loading