Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #10738 -- Fixed content type values for deferred and proxy models.

Models with deferred fields, or which are proxying for an existing
model, now return the same ContentType object as the real model they
reflect. Thanks to tomasz.elendt for help with fixing this.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10523 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 92824e71028d40009d32fc68d459b0c2242fb7fe 1 parent e12e0e1
Malcolm Tredinnick authored April 11, 2009
19  django/contrib/contenttypes/models.py
@@ -7,7 +7,7 @@ class ContentTypeManager(models.Manager):
7 7
     # Cache to avoid re-looking up ContentType objects all over the place.
8 8
     # This cache is shared by all the get_for_* methods.
9 9
     _cache = {}
10  
-    
  10
+
11 11
     def get_for_model(self, model):
12 12
         """
13 13
         Returns the ContentType object for a given model, creating the
@@ -15,22 +15,25 @@ def get_for_model(self, model):
15 15
         for the same model don't hit the database.
16 16
         """
17 17
         opts = model._meta
  18
+        while opts.proxy:
  19
+            model = opts.proxy_for_model
  20
+            opts = model._meta
18 21
         key = (opts.app_label, opts.object_name.lower())
19 22
         try:
20 23
             ct = self.__class__._cache[key]
21 24
         except KeyError:
22  
-            # Load or create the ContentType entry. The smart_unicode() is 
  25
+            # Load or create the ContentType entry. The smart_unicode() is
23 26
             # needed around opts.verbose_name_raw because name_raw might be a
24 27
             # django.utils.functional.__proxy__ object.
25 28
             ct, created = self.get_or_create(
26 29
                 app_label = opts.app_label,
27  
-                model = opts.object_name.lower(), 
  30
+                model = opts.object_name.lower(),
28 31
                 defaults = {'name': smart_unicode(opts.verbose_name_raw)},
29 32
             )
30 33
             self._add_to_cache(ct)
31  
-            
  34
+
32 35
         return ct
33  
-        
  36
+
34 37
     def get_for_id(self, id):
35 38
         """
36 39
         Lookup a ContentType by ID. Uses the same shared cache as get_for_model
@@ -44,7 +47,7 @@ def get_for_id(self, id):
44 47
             ct = self.get(pk=id)
45 48
             self._add_to_cache(ct)
46 49
         return ct
47  
-            
  50
+
48 51
     def clear_cache(self):
49 52
         """
50 53
         Clear out the content-type cache. This needs to happen during database
@@ -53,7 +56,7 @@ def clear_cache(self):
53 56
         this gets called).
54 57
         """
55 58
         self.__class__._cache.clear()
56  
-        
  59
+
57 60
     def _add_to_cache(self, ct):
58 61
         """Insert a ContentType into the cache."""
59 62
         model = ct.model_class()
@@ -66,7 +69,7 @@ class ContentType(models.Model):
66 69
     app_label = models.CharField(max_length=100)
67 70
     model = models.CharField(_('python model class name'), max_length=100)
68 71
     objects = ContentTypeManager()
69  
-    
  72
+
70 73
     class Meta:
71 74
         verbose_name = _('content type')
72 75
         verbose_name_plural = _('content types')
7  tests/modeltests/proxy_models/models.py
@@ -5,6 +5,7 @@
5 5
 providing a modified interface to the data from the base class.
6 6
 """
7 7
 
  8
+from django.contrib.contenttypes.models import ContentType
8 9
 from django.db import models
9 10
 
10 11
 
@@ -171,6 +172,12 @@ class LowerStatusPerson(MyPersonProxy):
171 172
 [<OtherPerson: barney>, <OtherPerson: fred>]
172 173
 >>> OtherPerson._default_manager.all()
173 174
 [<OtherPerson: barney>, <OtherPerson: wilma>]
  175
+
  176
+# A proxy has the same content type as the model it is proxying for (at the
  177
+# storage level, it is meant to be essentially indistinguishable).
  178
+>>> ctype = ContentType.objects.get_for_model
  179
+>>> ctype(Person) is ctype(OtherPerson)
  180
+True
174 181
 """}
175 182
 
176 183
 
10  tests/regressiontests/defer_regress/models.py
@@ -3,6 +3,7 @@
3 3
 """
4 4
 
5 5
 from django.conf import settings
  6
+from django.contrib.contenttypes.models import ContentType
6 7
 from django.db import connection, models
7 8
 
8 9
 class Item(models.Model):
@@ -91,5 +92,14 @@ def __unicode__(self):
91 92
 >>> Leaf.objects.select_related().only("child__name", "second_child__name")
92 93
 [<Leaf_Deferred_name_value: l1>]
93 94
 
  95
+Models instances with deferred fields should still return the same content
  96
+types as their non-deferred versions (bug #10738).
  97
+>>> ctype = ContentType.objects.get_for_model
  98
+>>> c1 = ctype(Item.objects.all()[0])
  99
+>>> c2 = ctype(Item.objects.defer("name")[0])
  100
+>>> c3 = ctype(Item.objects.only("name")[0])
  101
+>>> c1 is c2 is c3
  102
+True
  103
+
94 104
 """
95 105
 }

0 notes on commit 92824e7

Please sign in to comment.
Something went wrong with that request. Please try again.