diff options
| author | Simon Charette <charette.s@gmail.com> | 2012-05-29 17:55:20 -0400 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2012-06-08 23:07:58 +0300 |
| commit | b6d533af4d03f27ea957baa5fd70f7d0b942ef9a (patch) | |
| tree | 2a43e5b62d58c4de2456d4d5938dceba0a2c1a67 /django | |
| parent | 90985048fc1882483794e6734eb91401aefbe768 (diff) | |
Fixed #18399 – Added a way to get ContentTypes for proxy models
Added kwargs for_concrete_model and for_concrete_models to ContentType
methods get_for_model() and get_for_models(). By setting the flag to
False, it is possible to get the contenttype for proxy models.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/contenttypes/models.py | 17 | ||||
| -rw-r--r-- | django/contrib/contenttypes/tests.py | 88 |
2 files changed, 99 insertions, 6 deletions
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py index d588ff4d23..867351f6c8 100644 --- a/django/contrib/contenttypes/models.py +++ b/django/contrib/contenttypes/models.py @@ -16,20 +16,24 @@ class ContentTypeManager(models.Manager): self._add_to_cache(self.db, ct) return ct - def _get_opts(self, model): - return model._meta.concrete_model._meta + def _get_opts(self, model, for_concrete_model): + if for_concrete_model: + model = model._meta.concrete_model + elif model._deferred: + model = model._meta.proxy_for_model + return model._meta def _get_from_cache(self, opts): key = (opts.app_label, opts.object_name.lower()) return self.__class__._cache[self.db][key] - def get_for_model(self, model): + def get_for_model(self, model, for_concrete_model=True): """ Returns the ContentType object for a given model, creating the ContentType if necessary. Lookups are cached so that subsequent lookups for the same model don't hit the database. """ - opts = self._get_opts(model) + opts = self._get_opts(model, for_concrete_model) try: ct = self._get_from_cache(opts) except KeyError: @@ -45,10 +49,11 @@ class ContentTypeManager(models.Manager): return ct - def get_for_models(self, *models): + def get_for_models(self, *models, **kwargs): """ Given *models, returns a dictionary mapping {model: content_type}. """ + for_concrete_models = kwargs.pop('for_concrete_models', True) # Final results results = {} # models that aren't already in the cache @@ -56,7 +61,7 @@ class ContentTypeManager(models.Manager): needed_models = set() needed_opts = set() for model in models: - opts = self._get_opts(model) + opts = self._get_opts(model, for_concrete_models) try: ct = self._get_from_cache(opts) except KeyError: diff --git a/django/contrib/contenttypes/tests.py b/django/contrib/contenttypes/tests.py index 2eaa4c182e..0efc5222c0 100644 --- a/django/contrib/contenttypes/tests.py +++ b/django/contrib/contenttypes/tests.py @@ -11,6 +11,13 @@ from django.test import TestCase from django.utils.encoding import smart_str +class ConcreteModel(models.Model): + name = models.CharField(max_length=10) + +class ProxyModel(ConcreteModel): + class Meta: + proxy = True + class FooWithoutUrl(models.Model): """ Fake model not defining ``get_absolute_url`` for @@ -114,6 +121,87 @@ class ContentTypesTests(TestCase): FooWithUrl: ContentType.objects.get_for_model(FooWithUrl), }) + def test_get_for_concrete_model(self): + """ + Make sure the `for_concrete_model` kwarg correctly works + with concrete, proxy and deferred models + """ + concrete_model_ct = ContentType.objects.get_for_model(ConcreteModel) + + self.assertEqual(concrete_model_ct, + ContentType.objects.get_for_model(ProxyModel)) + + self.assertEqual(concrete_model_ct, + ContentType.objects.get_for_model(ConcreteModel, + for_concrete_model=False)) + + proxy_model_ct = ContentType.objects.get_for_model(ProxyModel, + for_concrete_model=False) + + self.assertNotEqual(concrete_model_ct, proxy_model_ct) + + # Make sure deferred model are correctly handled + ConcreteModel.objects.create(name="Concrete") + DeferredConcreteModel = ConcreteModel.objects.only('pk').get().__class__ + DeferredProxyModel = ProxyModel.objects.only('pk').get().__class__ + + self.assertEqual(concrete_model_ct, + ContentType.objects.get_for_model(DeferredConcreteModel)) + + self.assertEqual(concrete_model_ct, + ContentType.objects.get_for_model(DeferredConcreteModel, + for_concrete_model=False)) + + self.assertEqual(concrete_model_ct, + ContentType.objects.get_for_model(DeferredProxyModel)) + + self.assertEqual(proxy_model_ct, + ContentType.objects.get_for_model(DeferredProxyModel, + for_concrete_model=False)) + + def test_get_for_concrete_models(self): + """ + Make sure the `for_concrete_models` kwarg correctly works + with concrete, proxy and deferred models. + """ + concrete_model_ct = ContentType.objects.get_for_model(ConcreteModel) + + cts = ContentType.objects.get_for_models(ConcreteModel, ProxyModel) + self.assertEqual(cts, { + ConcreteModel: concrete_model_ct, + ProxyModel: concrete_model_ct, + }) + + proxy_model_ct = ContentType.objects.get_for_model(ProxyModel, + for_concrete_model=False) + cts = ContentType.objects.get_for_models(ConcreteModel, ProxyModel, + for_concrete_models=False) + self.assertEqual(cts, { + ConcreteModel: concrete_model_ct, + ProxyModel: proxy_model_ct, + }) + + # Make sure deferred model are correctly handled + ConcreteModel.objects.create(name="Concrete") + DeferredConcreteModel = ConcreteModel.objects.only('pk').get().__class__ + DeferredProxyModel = ProxyModel.objects.only('pk').get().__class__ + + cts = ContentType.objects.get_for_models(DeferredConcreteModel, + DeferredProxyModel) + self.assertEqual(cts, { + DeferredConcreteModel: concrete_model_ct, + DeferredProxyModel: concrete_model_ct, + }) + + cts = ContentType.objects.get_for_models(DeferredConcreteModel, + DeferredProxyModel, + for_concrete_models=False) + self.assertEqual(cts, { + DeferredConcreteModel: concrete_model_ct, + DeferredProxyModel: proxy_model_ct, + }) + + def test_shortcut_view(self): """ Check that the shortcut view (used for the admin "view on site" |
