| 262 | |
| 263 | class DeletionSignalsTest(TestCase): |
| 264 | """ |
| 265 | Deletion signals should be sent correctly in inheritance scenarios |
| 266 | involving proxies (as described in #18094). |
| 267 | |
| 268 | """ |
| 269 | |
| 270 | senders = (File, Image, Photo, |
| 271 | BarFile, BarFileProxy1, BarFileProxy1Proxy, BarFileProxy2) |
| 272 | |
| 273 | def setUp(self): |
| 274 | self.clear_received_senders() |
| 275 | for sender in self.senders: |
| 276 | models.signals.pre_delete.connect(self.pre_delete_receiver, sender) |
| 277 | models.signals.post_delete.connect(self.post_delete_receiver, sender) |
| 278 | |
| 279 | def tearDown(self): |
| 280 | for sender in self.senders: |
| 281 | models.signals.pre_delete.disconnect(self.pre_delete_receiver, sender) |
| 282 | models.signals.post_delete.disconnect(self.post_delete_receiver, sender) |
| 283 | |
| 284 | def clear_received_senders(self): |
| 285 | self.pre_delete_senders = [] |
| 286 | self.post_delete_senders = [] |
| 287 | |
| 288 | def pre_delete_receiver(self, sender, **kwargs): |
| 289 | self.pre_delete_senders.append(sender) |
| 290 | |
| 291 | def post_delete_receiver(self, sender, **kwargs): |
| 292 | self.post_delete_senders.append(sender) |
| 293 | |
| 294 | def test_simple_proxy_deletion(self): |
| 295 | """ |
| 296 | Triggering deletion from a concrete model instance should send the same |
| 297 | signals as an instance of a proxy of this model. Signals should be |
| 298 | orderly sent for all proxies of the deleted concrete model (based on |
| 299 | their inheritance depth and declaration order) and finally for the |
| 300 | concrete model itself. |
| 301 | |
| 302 | """ |
| 303 | expected_senders = [Photo, Image, File] |
| 304 | |
| 305 | File.objects.create().delete() |
| 306 | self.assertEqual(self.pre_delete_senders, expected_senders) |
| 307 | self.assertEqual(self.post_delete_senders, expected_senders) |
| 308 | |
| 309 | self.clear_received_senders() |
| 310 | |
| 311 | Image.objects.create().delete() |
| 312 | self.assertEqual(self.pre_delete_senders, expected_senders) |
| 313 | self.assertEqual(self.post_delete_senders, expected_senders) |
| 314 | |
| 315 | self.clear_received_senders() |
| 316 | |
| 317 | Photo.objects.create().delete() |
| 318 | self.assertEqual(self.pre_delete_senders, expected_senders) |
| 319 | self.assertEqual(self.post_delete_senders, expected_senders) |
| 320 | |
| 321 | def test_multi_table_inheritance_proxy_deletion(self): |
| 322 | """ |
| 323 | In a multi-table inheritance scenario, deletion signals should also be |
| 324 | orderly sent for all proxies of concrete model involved in the deletion. |
| 325 | |
| 326 | """ |
| 327 | expected_senders = [BarFileProxy1Proxy, BarFileProxy1, BarFileProxy2, |
| 328 | BarFile, Photo, Image, File] |
| 329 | |
| 330 | BarFile.objects.create().delete() |
| 331 | self.assertEqual(self.pre_delete_senders, expected_senders) |
| 332 | self.assertEqual(self.post_delete_senders, expected_senders) |
| 333 | |
| 334 | self.clear_received_senders() |
| 335 | |
| 336 | BarFileProxy1.objects.create().delete() |
| 337 | self.assertEqual(self.pre_delete_senders, expected_senders) |
| 338 | self.assertEqual(self.post_delete_senders, expected_senders) |
| 339 | |
| 340 | self.clear_received_senders() |
| 341 | |
| 342 | BarFileProxy2.objects.create().delete() |
| 343 | self.assertEqual(self.pre_delete_senders, expected_senders) |
| 344 | self.assertEqual(self.post_delete_senders, expected_senders) |
| 345 | |
| 346 | self.clear_received_senders() |
| 347 | |
| 348 | BarFileProxy1Proxy.objects.create().delete() |
| 349 | self.assertEqual(self.pre_delete_senders, expected_senders) |
| 350 | self.assertEqual(self.post_delete_senders, expected_senders) |