Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #17678 -- Corrected setup of _meta.proxy_for_model and added _m…

…eta.concrete_model. Thanks Anssi Kääriäinen.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17573 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 354c84d277e3a9516cd2af1567eb02cb4da1a3e4 1 parent 3ac0961
Carl Meyer authored February 22, 2012
6  django/contrib/contenttypes/models.py
@@ -17,11 +17,7 @@ def get_by_natural_key(self, app_label, model):
17 17
         return ct
18 18
 
19 19
     def _get_opts(self, model):
20  
-        opts = model._meta
21  
-        while opts.proxy:
22  
-            model = opts.proxy_for_model
23  
-            opts = model._meta
24  
-        return opts
  20
+        return model._meta.concrete_model._meta
25 21
 
26 22
     def _get_from_cache(self, opts):
27 23
         key = (opts.app_label, opts.object_name.lower())
3  django/contrib/gis/db/models/sql/compiler.py
@@ -2,7 +2,6 @@
2 2
 from django.db.backends.util import truncate_name, typecast_timestamp
3 3
 from django.db.models.sql import compiler
4 4
 from django.db.models.sql.constants import TABLE_NAME, MULTI
5  
-from django.db.models.sql.query import get_proxied_model
6 5
 
7 6
 SQLCompiler = compiler.SQLCompiler
8 7
 
@@ -116,7 +115,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
116 115
         aliases = set()
117 116
         only_load = self.deferred_to_columns()
118 117
         # Skip all proxy to the root proxied model
119  
-        proxied_model = get_proxied_model(opts)
  118
+        proxied_model = opts.concrete_model
120 119
 
121 120
         if start_alias:
122 121
             seen = {None: start_alias}
9  django/db/models/base.py
@@ -122,9 +122,10 @@ def __new__(cls, name, bases, attrs):
122 122
             if (new_class._meta.local_fields or
123 123
                     new_class._meta.local_many_to_many):
124 124
                 raise FieldError("Proxy model '%s' contains model fields." % name)
125  
-            while base._meta.proxy:
126  
-                base = base._meta.proxy_for_model
127 125
             new_class._meta.setup_proxy(base)
  126
+            new_class._meta.concrete_model = base._meta.concrete_model
  127
+        else:
  128
+            new_class._meta.concrete_model = new_class
128 129
 
129 130
         # Do the appropriate setup for any model parents.
130 131
         o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
@@ -149,9 +150,7 @@ def __new__(cls, name, bases, attrs):
149 150
                                         (field.name, name, base.__name__))
150 151
             if not base._meta.abstract:
151 152
                 # Concrete classes...
152  
-                while base._meta.proxy:
153  
-                    # Skip over a proxy class to the "real" base it proxies.
154  
-                    base = base._meta.proxy_for_model
  153
+                base = base._meta.concrete_model
155 154
                 if base in o2o_map:
156 155
                     field = o2o_map[base]
157 156
                 elif not is_proxy:
9  django/db/models/options.py
@@ -40,7 +40,16 @@ def __init__(self, meta, app_label=None):
40 40
         self.abstract = False
41 41
         self.managed = True
42 42
         self.proxy = False
  43
+        # For any class which is a proxy (including automatically created
  44
+        # classes for deferred object loading) the proxy_for_model tells
  45
+        # which class this model is proxying. Note that proxy_for_model
  46
+        # can create a chain of proxy models. For non-proxy models the
  47
+        # variable is always None.
43 48
         self.proxy_for_model = None
  49
+        # For any non-abstract class the concrete class is the model
  50
+        # in the end of the proxy_for_model chain. In particular, for
  51
+        # concrete models the concrete_model is always the class itself.
  52
+        self.concrete_model = None
44 53
         self.parents = SortedDict()
45 54
         self.duplicate_targets = {}
46 55
         self.auto_created = False
4  django/db/models/sql/compiler.py
@@ -7,7 +7,7 @@
7 7
 from django.db.models.sql.constants import *
8 8
 from django.db.models.sql.datastructures import EmptyResultSet
9 9
 from django.db.models.sql.expressions import SQLEvaluator
10  
-from django.db.models.sql.query import get_proxied_model, get_order_dir, Query
  10
+from django.db.models.sql.query import get_order_dir, Query
11 11
 from django.db.utils import DatabaseError
12 12
 
13 13
 
@@ -266,7 +266,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
266 266
         aliases = set()
267 267
         only_load = self.deferred_to_columns()
268 268
         # Skip all proxy to the root proxied model
269  
-        proxied_model = get_proxied_model(opts)
  269
+        proxied_model = opts.concrete_model
270 270
 
271 271
         if start_alias:
272 272
             seen = {None: start_alias}
19  django/db/models/sql/query.py
@@ -575,10 +575,7 @@ def deferred_to_data(self, target, callback):
575 575
             return
576 576
         orig_opts = self.model._meta
577 577
         seen = {}
578  
-        if orig_opts.proxy:
579  
-            must_include = {orig_opts.proxy_for_model: set([orig_opts.pk])}
580  
-        else:
581  
-            must_include = {self.model: set([orig_opts.pk])}
  578
+        must_include = {orig_opts.concrete_model: set([orig_opts.pk])}
582 579
         for field_name in field_names:
583 580
             parts = field_name.split(LOOKUP_SEP)
584 581
             cur_model = self.model
@@ -586,7 +583,7 @@ def deferred_to_data(self, target, callback):
586 583
             for name in parts[:-1]:
587 584
                 old_model = cur_model
588 585
                 source = opts.get_field_by_name(name)[0]
589  
-                cur_model = opts.get_field_by_name(name)[0].rel.to
  586
+                cur_model = source.rel.to
590 587
                 opts = cur_model._meta
591 588
                 # Even if we're "just passing through" this model, we must add
592 589
                 # both the current model's pk and the related reference field
@@ -946,7 +943,7 @@ def setup_inherited_models(self):
946 943
         seen = {None: root_alias}
947 944
 
948 945
         # Skip all proxy to the root proxied model
949  
-        proxied_model = get_proxied_model(opts)
  946
+        proxied_model = opts.concrete_model
950 947
 
951 948
         for field, model in opts.get_fields_with_model():
952 949
             if model not in seen:
@@ -1325,7 +1322,7 @@ def setup_joins(self, names, opts, alias, dupe_multis, allow_many=True,
1325 1322
             if model:
1326 1323
                 # The field lives on a base class of the current model.
1327 1324
                 # Skip the chain of proxy to the concrete proxied model
1328  
-                proxied_model = get_proxied_model(opts)
  1325
+                proxied_model = opts.concrete_model
1329 1326
 
1330 1327
                 for int_model in opts.get_base_chain(model):
1331 1328
                     if int_model is proxied_model:
@@ -1990,11 +1987,3 @@ def add_to_dict(data, key, value):
1990 1987
         data[key].add(value)
1991 1988
     else:
1992 1989
         data[key] = set([value])
1993  
-
1994  
-def get_proxied_model(opts):
1995  
-    int_opts = opts
1996  
-    proxied_model = None
1997  
-    while int_opts.proxy:
1998  
-        proxied_model = int_opts.proxy_for_model
1999  
-        int_opts = proxied_model._meta
2000  
-    return proxied_model
6  tests/modeltests/proxy_models/tests.py
@@ -232,6 +232,12 @@ def test_user_userproxy_userproxyproxy(self):
232 232
         resp = [u.name for u in UserProxyProxy.objects.all()]
233 233
         self.assertEqual(resp, ['Bruce'])
234 234
 
  235
+    def test_proxy_for_model(self):
  236
+        self.assertEqual(UserProxy, UserProxyProxy._meta.proxy_for_model)
  237
+
  238
+    def test_concrete_model(self):
  239
+        self.assertEqual(User, UserProxyProxy._meta.concrete_model)
  240
+
235 241
     def test_proxy_delete(self):
236 242
         """
237 243
         Proxy objects can be deleted

0 notes on commit 354c84d

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