summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2012-05-29 17:55:20 -0400
committerAnssi Kääriäinen <akaariai@gmail.com>2012-06-08 23:07:58 +0300
commitb6d533af4d03f27ea957baa5fd70f7d0b942ef9a (patch)
tree2a43e5b62d58c4de2456d4d5938dceba0a2c1a67 /django
parent90985048fc1882483794e6734eb91401aefbe768 (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.py17
-rw-r--r--django/contrib/contenttypes/tests.py88
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"