Ticket #13552: 13552-take-3.diff
File 13552-take-3.diff, 14.3 KB (added by , 14 years ago) |
---|
-
AUTHORS
diff --git a/AUTHORS b/AUTHORS
a b 189 189 martin.glueck@gmail.com 190 190 Artyom Gnilov <boobsd@gmail.com> 191 191 Ben Godfrey <http://aftnn.org> 192 Andrew Godwin <andrew@aeracode.org> 192 193 GomoX <gomo@datafull.com> 193 194 Guilherme Mesquita Gondim <semente@taurinus.org> 194 195 Mario Gonzalez <gonzalemario@gmail.com> -
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py
a b 456 456 meta = cls._meta 457 457 458 458 if origin and not meta.auto_created: 459 signals.pre_save.send(sender=origin, instance=self, raw=raw )459 signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using) 460 460 461 461 # If we are in a raw save, save the object exactly as presented. 462 462 # That means that we don't try to be smart about saving attributes … … 540 540 # Signal that the save is complete 541 541 if origin and not meta.auto_created: 542 542 signals.post_save.send(sender=origin, instance=self, 543 created=(not record_exists), raw=raw )543 created=(not record_exists), raw=raw, using=using) 544 544 545 545 save_base.alters_data = True 546 546 -
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
a b 566 566 # duplicate data row for symmetrical reverse entries. 567 567 signals.m2m_changed.send(sender=rel.through, action='pre_add', 568 568 instance=self.instance, reverse=self.reverse, 569 model=self.model, pk_set=new_ids )569 model=self.model, pk_set=new_ids, using=db) 570 570 # Add the ones that aren't there already 571 571 for obj_id in new_ids: 572 572 self.through._default_manager.using(db).create(**{ … … 578 578 # duplicate data row for symmetrical reverse entries. 579 579 signals.m2m_changed.send(sender=rel.through, action='post_add', 580 580 instance=self.instance, reverse=self.reverse, 581 model=self.model, pk_set=new_ids )581 model=self.model, pk_set=new_ids, using=db) 582 582 583 583 def _remove_items(self, source_field_name, target_field_name, *objs): 584 584 # source_col_name: the PK colname in join_table for the source object … … 594 594 old_ids.add(obj.pk) 595 595 else: 596 596 old_ids.add(obj) 597 # Work out what DB we're operating on 598 db = router.db_for_write(self.through.__class__, instance=self.instance) 599 # Send a signal to the other end if need be. 597 600 if self.reverse or source_field_name == self.source_field_name: 598 601 # Don't send the signal when we are deleting the 599 602 # duplicate data row for symmetrical reverse entries. 600 603 signals.m2m_changed.send(sender=rel.through, action="pre_remove", 601 604 instance=self.instance, reverse=self.reverse, 602 model=self.model, pk_set=old_ids )605 model=self.model, pk_set=old_ids, using=db) 603 606 # Remove the specified objects from the join table 604 db = router.db_for_write(self.through.__class__, instance=self.instance)605 607 self.through._default_manager.using(db).filter(**{ 606 608 source_field_name: self._pk_val, 607 609 '%s__in' % target_field_name: old_ids … … 611 613 # duplicate data row for symmetrical reverse entries. 612 614 signals.m2m_changed.send(sender=rel.through, action="post_remove", 613 615 instance=self.instance, reverse=self.reverse, 614 model=self.model, pk_set=old_ids )616 model=self.model, pk_set=old_ids, using=db) 615 617 616 618 def _clear_items(self, source_field_name): 619 db = router.db_for_write(self.through.__class__, instance=self.instance) 617 620 # source_col_name: the PK colname in join_table for the source object 618 621 if self.reverse or source_field_name == self.source_field_name: 619 622 # Don't send the signal when we are clearing the 620 623 # duplicate data rows for symmetrical reverse entries. 621 624 signals.m2m_changed.send(sender=rel.through, action="pre_clear", 622 625 instance=self.instance, reverse=self.reverse, 623 model=self.model, pk_set=None) 624 db = router.db_for_write(self.through.__class__, instance=self.instance) 626 model=self.model, pk_set=None, using=db) 625 627 self.through._default_manager.using(db).filter(**{ 626 628 source_field_name: self._pk_val 627 629 }).delete() … … 630 632 # duplicate data rows for symmetrical reverse entries. 631 633 signals.m2m_changed.send(sender=rel.through, action="post_clear", 632 634 instance=self.instance, reverse=self.reverse, 633 model=self.model, pk_set=None )635 model=self.model, pk_set=None, using=db) 634 636 635 637 return ManyRelatedManager 636 638 -
django/db/models/query.py
diff --git a/django/db/models/query.py b/django/db/models/query.py
a b 1311 1311 # Pre-notify all instances to be deleted. 1312 1312 for pk_val, instance in items: 1313 1313 if not cls._meta.auto_created: 1314 signals.pre_delete.send(sender=cls, instance=instance) 1314 signals.pre_delete.send(sender=cls, instance=instance, 1315 using=using) 1315 1316 1316 1317 pk_list = [pk for pk,instance in items] 1317 1318 … … 1343 1344 setattr(instance, field.attname, None) 1344 1345 1345 1346 if not cls._meta.auto_created: 1346 signals.post_delete.send(sender=cls, instance=instance )1347 signals.post_delete.send(sender=cls, instance=instance, using=using) 1347 1348 setattr(instance, cls._meta.pk.attname, None) 1348 1349 1349 1350 if forced_managed: -
django/db/models/signals.py
diff --git a/django/db/models/signals.py b/django/db/models/signals.py
a b 5 5 pre_init = Signal(providing_args=["instance", "args", "kwargs"]) 6 6 post_init = Signal(providing_args=["instance"]) 7 7 8 pre_save = Signal(providing_args=["instance", "raw" ])9 post_save = Signal(providing_args=["instance", "raw", "created" ])8 pre_save = Signal(providing_args=["instance", "raw", "using"]) 9 post_save = Signal(providing_args=["instance", "raw", "created", "using"]) 10 10 11 pre_delete = Signal(providing_args=["instance" ])12 post_delete = Signal(providing_args=["instance" ])11 pre_delete = Signal(providing_args=["instance", "using"]) 12 post_delete = Signal(providing_args=["instance", "using"]) 13 13 14 14 post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"]) 15 15 16 m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set" ])16 m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"]) -
docs/ref/signals.txt
diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt
a b 113 113 ``instance`` 114 114 The actual instance being saved. 115 115 116 ``using`` 117 The database alias being used. 118 116 119 post_save 117 120 --------- 118 121 … … 133 136 ``created`` 134 137 A boolean; ``True`` if a new record was created. 135 138 139 ``using`` 140 The database alias being used. 141 136 142 pre_delete 137 143 ---------- 138 144 … … 150 156 ``instance`` 151 157 The actual instance being deleted. 152 158 159 ``using`` 160 The database alias being used. 161 153 162 post_delete 154 163 ----------- 155 164 … … 170 179 Note that the object will no longer be in the database, so be very 171 180 careful what you do with this instance. 172 181 182 ``using`` 183 The database alias being used. 184 173 185 m2m_changed 174 186 ----------- 175 187 … … 228 240 229 241 For the ``"clear"`` action, this is ``None``. 230 242 243 ``using`` 244 The database alias being used. 245 231 246 For example, if a ``Pizza`` can have multiple ``Topping`` objects, modeled 232 247 like this: 233 248 … … 266 281 ``Pizza``) 267 282 268 283 ``pk_set`` ``[t.id]`` (since only ``Topping t`` was added to the relation) 284 285 ``using`` ``"default"`` (since the default router sends writes here) 269 286 ============== ============================================================ 270 287 271 288 And if we would then do something like this: … … 293 310 294 311 ``pk_set`` ``[p.id]`` (since only ``Pizza p`` was removed from the 295 312 relation) 313 314 ``using`` ``"default"`` (since the default router sends writes here) 296 315 ============== ============================================================ 297 316 298 317 class_prepared -
tests/modeltests/signals/models.py
diff --git a/tests/modeltests/signals/models.py b/tests/modeltests/signals/models.py
a b 11 11 def __unicode__(self): 12 12 return u"%s %s" % (self.first_name, self.last_name) 13 13 14 class Project(models.Model): 15 people = models.ManyToManyField(Person) 16 17 14 18 def pre_save_test(signal, sender, instance, **kwargs): 15 19 print 'pre_save signal,', instance 16 20 if kwargs.get('raw'): -
tests/modeltests/signals/tests.py
diff --git a/tests/modeltests/signals/tests.py b/tests/modeltests/signals/tests.py
a b 1 1 from django.db.models import signals 2 from django.db import DEFAULT_DB_ALIAS, router 2 3 from django.test import TestCase 3 from modeltests.signals.models import Person 4 from modeltests.signals.models import Person, Project 4 5 5 class MyReceiver(object): 6 class DisconnectReceiver(object): 7 """ 8 Used to test the disconnection of signals. 9 """ 6 10 def __init__(self, param): 7 11 self.param = param 8 12 self._run = False … … 10 14 def __call__(self, signal, sender, **kwargs): 11 15 self._run = True 12 16 signal.disconnect(receiver=self, sender=sender) 17 18 class DatabaseReceiver(object): 19 """ 20 Used in the tests for the database argument in signals (#13552) 21 """ 22 def __call__(self, signal, sender, **kwargs): 23 self._database = kwargs['using'] 24 25 class TestRouter(object): 26 """ 27 A router that sends all writes to the other database. 28 """ 29 def db_for_write(self, model, **hints): 30 return "other" 13 31 14 32 class SignalTests(TestCase): 33 34 multi_db = True 35 36 def _write_to_other(self): 37 "Sends all writes to 'other'." 38 self.old_routers = router.routers 39 router.routers = [TestRouter()] 40 41 def _write_to_default(self): 42 "Sends all writes to the default DB" 43 router.routers = self.old_routers 44 15 45 def test_disconnect_in_dispatch(self): 16 46 """ 17 47 Test that signals that disconnect when being called don't mess future 18 48 dispatching. 19 49 """ 20 a, b = MyReceiver(1), MyReceiver(2)50 a, b = DisconnectReceiver(1), DisconnectReceiver(2) 21 51 signals.post_save.connect(sender=Person, receiver=a) 22 52 signals.post_save.connect(sender=Person, receiver=b) 23 53 p = Person.objects.create(first_name='John', last_name='Smith') … … 25 55 self.failUnless(a._run) 26 56 self.failUnless(b._run) 27 57 self.assertEqual(signals.post_save.receivers, []) 28 58 59 def test_database_arg_save_and_delete(self): 60 """ 61 Tests that the pre/post_save signal contains the correct database. 62 (#13552) 63 """ 64 # Make some signal receivers 65 pre_save_receiver = DatabaseReceiver() 66 post_save_receiver = DatabaseReceiver() 67 pre_delete_receiver = DatabaseReceiver() 68 post_delete_receiver = DatabaseReceiver() 69 # Make model and connect receivers 70 signals.pre_save.connect(sender=Person, receiver=pre_save_receiver) 71 signals.post_save.connect(sender=Person, receiver=post_save_receiver) 72 signals.pre_delete.connect(sender=Person, receiver=pre_delete_receiver) 73 signals.post_delete.connect(sender=Person, receiver=post_delete_receiver) 74 p = Person.objects.create(first_name='Darth', last_name='Vader') 75 # Save and test receivers got calls 76 p.save() 77 self.assertEqual(pre_save_receiver._database, DEFAULT_DB_ALIAS) 78 self.assertEqual(post_save_receiver._database, DEFAULT_DB_ALIAS) 79 # Delete, and test 80 p.delete() 81 self.assertEqual(pre_delete_receiver._database, DEFAULT_DB_ALIAS) 82 self.assertEqual(post_delete_receiver._database, DEFAULT_DB_ALIAS) 83 # Save again to a different database 84 p.save(using="other") 85 self.assertEqual(pre_save_receiver._database, "other") 86 self.assertEqual(post_save_receiver._database, "other") 87 # Delete, and test 88 p.delete(using="other") 89 self.assertEqual(pre_delete_receiver._database, "other") 90 self.assertEqual(post_delete_receiver._database, "other") 91 92 def test_database_arg_m2m(self): 93 """ 94 Test that the m2m_changed signal has a correct database arg (#13552) 95 """ 96 # Make a receiver 97 receiver = DatabaseReceiver() 98 # Connect it, and make the models 99 signals.m2m_changed.connect(receiver=receiver) 100 pe = Person.objects.create(first_name='Jane', last_name='Smith') 101 pr = Project.objects.create() 102 # Test addition 103 pr.people.add(pe) 104 self.assertEqual(receiver._database, DEFAULT_DB_ALIAS) 105 self._write_to_other() 106 pr.people.add(pe) 107 self._write_to_default() 108 self.assertEqual(receiver._database, "other") 109 # Test removal 110 pr.people.remove(pe) 111 self.assertEqual(receiver._database, DEFAULT_DB_ALIAS) 112 self._write_to_other() 113 pr.people.remove(pe) 114 self._write_to_default() 115 self.assertEqual(receiver._database, "other") 116 # Test clearing 117 pr.people.clear() 118 self.assertEqual(receiver._database, DEFAULT_DB_ALIAS) 119 self._write_to_other() 120 pr.people.clear() 121 self._write_to_default() 122 self.assertEqual(receiver._database, "other") 123 No newline at end of file