summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/contenttypes/models.py19
-rw-r--r--tests/modeltests/proxy_models/models.py7
-rw-r--r--tests/regressiontests/defer_regress/models.py10
3 files changed, 28 insertions, 8 deletions
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index 4df1edcc75..def7ce6986 100644
--- a/django/contrib/contenttypes/models.py
+++ b/django/contrib/contenttypes/models.py
@@ -7,7 +7,7 @@ class ContentTypeManager(models.Manager):
# Cache to avoid re-looking up ContentType objects all over the place.
# This cache is shared by all the get_for_* methods.
_cache = {}
-
+
def get_for_model(self, model):
"""
Returns the ContentType object for a given model, creating the
@@ -15,22 +15,25 @@ class ContentTypeManager(models.Manager):
for the same model don't hit the database.
"""
opts = model._meta
+ while opts.proxy:
+ model = opts.proxy_for_model
+ opts = model._meta
key = (opts.app_label, opts.object_name.lower())
try:
ct = self.__class__._cache[key]
except KeyError:
- # Load or create the ContentType entry. The smart_unicode() is
+ # Load or create the ContentType entry. The smart_unicode() is
# needed around opts.verbose_name_raw because name_raw might be a
# django.utils.functional.__proxy__ object.
ct, created = self.get_or_create(
app_label = opts.app_label,
- model = opts.object_name.lower(),
+ model = opts.object_name.lower(),
defaults = {'name': smart_unicode(opts.verbose_name_raw)},
)
self._add_to_cache(ct)
-
+
return ct
-
+
def get_for_id(self, id):
"""
Lookup a ContentType by ID. Uses the same shared cache as get_for_model
@@ -44,7 +47,7 @@ class ContentTypeManager(models.Manager):
ct = self.get(pk=id)
self._add_to_cache(ct)
return ct
-
+
def clear_cache(self):
"""
Clear out the content-type cache. This needs to happen during database
@@ -53,7 +56,7 @@ class ContentTypeManager(models.Manager):
this gets called).
"""
self.__class__._cache.clear()
-
+
def _add_to_cache(self, ct):
"""Insert a ContentType into the cache."""
model = ct.model_class()
@@ -66,7 +69,7 @@ class ContentType(models.Model):
app_label = models.CharField(max_length=100)
model = models.CharField(_('python model class name'), max_length=100)
objects = ContentTypeManager()
-
+
class Meta:
verbose_name = _('content type')
verbose_name_plural = _('content types')
diff --git a/tests/modeltests/proxy_models/models.py b/tests/modeltests/proxy_models/models.py
index 275b5207cc..ab381129cf 100644
--- a/tests/modeltests/proxy_models/models.py
+++ b/tests/modeltests/proxy_models/models.py
@@ -5,6 +5,7 @@ than using a new table of their own. This allows them to act as simple proxies,
providing a modified interface to the data from the base class.
"""
+from django.contrib.contenttypes.models import ContentType
from django.db import models
@@ -171,6 +172,12 @@ FieldError: Proxy model 'NoNewFields' contains model fields.
[<OtherPerson: barney>, <OtherPerson: fred>]
>>> OtherPerson._default_manager.all()
[<OtherPerson: barney>, <OtherPerson: wilma>]
+
+# A proxy has the same content type as the model it is proxying for (at the
+# storage level, it is meant to be essentially indistinguishable).
+>>> ctype = ContentType.objects.get_for_model
+>>> ctype(Person) is ctype(OtherPerson)
+True
"""}
diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py
index e2a5944f92..11ce1557fe 100644
--- a/tests/regressiontests/defer_regress/models.py
+++ b/tests/regressiontests/defer_regress/models.py
@@ -3,6 +3,7 @@ Regression tests for defer() / only() behavior.
"""
from django.conf import settings
+from django.contrib.contenttypes.models import ContentType
from django.db import connection, models
class Item(models.Model):
@@ -91,5 +92,14 @@ u'c1'
>>> Leaf.objects.select_related().only("child__name", "second_child__name")
[<Leaf_Deferred_name_value: l1>]
+Models instances with deferred fields should still return the same content
+types as their non-deferred versions (bug #10738).
+>>> ctype = ContentType.objects.get_for_model
+>>> c1 = ctype(Item.objects.all()[0])
+>>> c2 = ctype(Item.objects.defer("name")[0])
+>>> c3 = ctype(Item.objects.only("name")[0])
+>>> c1 is c2 is c3
+True
+
"""
}