mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.10.x] Fixed #26686 -- Fixed crash when registering model signals with abstract senders.
Backport of 08014fe75b from master
			
			
This commit is contained in:
		| @@ -3,6 +3,7 @@ from functools import partial | |||||||
|  |  | ||||||
| from django.db.models.utils import make_model_tuple | from django.db.models.utils import make_model_tuple | ||||||
| from django.dispatch import Signal | from django.dispatch import Signal | ||||||
|  | from django.utils import six | ||||||
| from django.utils.deprecation import RemovedInDjango20Warning | from django.utils.deprecation import RemovedInDjango20Warning | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -15,15 +16,15 @@ class ModelSignal(Signal): | |||||||
|     of the `app_label.ModelName` form. |     of the `app_label.ModelName` form. | ||||||
|     """ |     """ | ||||||
|     def _lazy_method(self, method, apps, receiver, sender, **kwargs): |     def _lazy_method(self, method, apps, receiver, sender, **kwargs): | ||||||
|  |         from django.db.models.options import Options | ||||||
|  |  | ||||||
|         # This partial takes a single optional argument named "sender". |         # This partial takes a single optional argument named "sender". | ||||||
|         partial_method = partial(method, receiver, **kwargs) |         partial_method = partial(method, receiver, **kwargs) | ||||||
|         # import models here to avoid a circular import |         if isinstance(sender, six.string_types): | ||||||
|         from django.db import models |             apps = apps or Options.default_apps | ||||||
|         if isinstance(sender, models.Model) or sender is None: |             apps.lazy_model_operation(partial_method, make_model_tuple(sender)) | ||||||
|             # Skip lazy_model_operation to get a return value for disconnect() |         else: | ||||||
|             return partial_method(sender) |             return partial_method(sender) | ||||||
|         apps = apps or models.base.Options.default_apps |  | ||||||
|         apps.lazy_model_operation(partial_method, make_model_tuple(sender)) |  | ||||||
|  |  | ||||||
|     def connect(self, receiver, sender=None, weak=True, dispatch_uid=None, apps=None): |     def connect(self, receiver, sender=None, weak=True, dispatch_uid=None, apps=None): | ||||||
|         self._lazy_method(super(ModelSignal, self).connect, apps, receiver, sender, dispatch_uid=dispatch_uid) |         self._lazy_method(super(ModelSignal, self).connect, apps, receiver, sender, dispatch_uid=dispatch_uid) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||||
|  |  | ||||||
|  | from django.apps.registry import Apps | ||||||
| from django.db import models | from django.db import models | ||||||
| from django.db.models import signals | from django.db.models import signals | ||||||
| from django.dispatch import receiver | from django.dispatch import receiver | ||||||
| @@ -317,3 +318,14 @@ class LazyModelRefTest(BaseSignalTest): | |||||||
|  |  | ||||||
|         Created() |         Created() | ||||||
|         self.assertEqual(received, []) |         self.assertEqual(received, []) | ||||||
|  |  | ||||||
|  |     def test_register_model_class_senders_immediately(self): | ||||||
|  |         """ | ||||||
|  |         Model signals registered with model classes as senders don't use the | ||||||
|  |         Apps.lazy_model_operation() mechanism. | ||||||
|  |         """ | ||||||
|  |         # Book isn't registered with apps2, so it will linger in | ||||||
|  |         # apps2._pending_operations if ModelSignal does the wrong thing. | ||||||
|  |         apps2 = Apps() | ||||||
|  |         signals.post_init.connect(self.receiver, sender=Book, apps=apps2) | ||||||
|  |         self.assertEqual(list(apps2._pending_operations), []) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user