Author: carljm
Date: 2012-02-21 21:26:50 -0800 (Tue, 21 Feb 2012)
New Revision: 17573

Modified:
   django/trunk/django/contrib/contenttypes/models.py
   django/trunk/django/contrib/gis/db/models/sql/compiler.py
   django/trunk/django/db/models/base.py
   django/trunk/django/db/models/options.py
   django/trunk/django/db/models/sql/compiler.py
   django/trunk/django/db/models/sql/query.py
   django/trunk/tests/modeltests/proxy_models/tests.py
Log:
Fixed #17678 -- Corrected setup of _meta.proxy_for_model and added 
_meta.concrete_model. Thanks Anssi K?\195?\164?\195?\164ri?\195?\164inen.

Modified: django/trunk/django/contrib/contenttypes/models.py
===================================================================
--- django/trunk/django/contrib/contenttypes/models.py  2012-02-22 00:52:19 UTC 
(rev 17572)
+++ django/trunk/django/contrib/contenttypes/models.py  2012-02-22 05:26:50 UTC 
(rev 17573)
@@ -17,11 +17,7 @@
         return ct
 
     def _get_opts(self, model):
-        opts = model._meta
-        while opts.proxy:
-            model = opts.proxy_for_model
-            opts = model._meta
-        return opts
+        return model._meta.concrete_model._meta
 
     def _get_from_cache(self, opts):
         key = (opts.app_label, opts.object_name.lower())

Modified: django/trunk/django/contrib/gis/db/models/sql/compiler.py
===================================================================
--- django/trunk/django/contrib/gis/db/models/sql/compiler.py   2012-02-22 
00:52:19 UTC (rev 17572)
+++ django/trunk/django/contrib/gis/db/models/sql/compiler.py   2012-02-22 
05:26:50 UTC (rev 17573)
@@ -2,7 +2,6 @@
 from django.db.backends.util import truncate_name, typecast_timestamp
 from django.db.models.sql import compiler
 from django.db.models.sql.constants import TABLE_NAME, MULTI
-from django.db.models.sql.query import get_proxied_model
 
 SQLCompiler = compiler.SQLCompiler
 
@@ -116,7 +115,7 @@
         aliases = set()
         only_load = self.deferred_to_columns()
         # Skip all proxy to the root proxied model
-        proxied_model = get_proxied_model(opts)
+        proxied_model = opts.concrete_model
 
         if start_alias:
             seen = {None: start_alias}

Modified: django/trunk/django/db/models/base.py
===================================================================
--- django/trunk/django/db/models/base.py       2012-02-22 00:52:19 UTC (rev 
17572)
+++ django/trunk/django/db/models/base.py       2012-02-22 05:26:50 UTC (rev 
17573)
@@ -122,9 +122,10 @@
             if (new_class._meta.local_fields or
                     new_class._meta.local_many_to_many):
                 raise FieldError("Proxy model '%s' contains model fields." % 
name)
-            while base._meta.proxy:
-                base = base._meta.proxy_for_model
             new_class._meta.setup_proxy(base)
+            new_class._meta.concrete_model = base._meta.concrete_model
+        else:
+            new_class._meta.concrete_model = new_class
 
         # Do the appropriate setup for any model parents.
         o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
@@ -149,9 +150,7 @@
                                         (field.name, name, base.__name__))
             if not base._meta.abstract:
                 # Concrete classes...
-                while base._meta.proxy:
-                    # Skip over a proxy class to the "real" base it proxies.
-                    base = base._meta.proxy_for_model
+                base = base._meta.concrete_model
                 if base in o2o_map:
                     field = o2o_map[base]
                 elif not is_proxy:

Modified: django/trunk/django/db/models/options.py
===================================================================
--- django/trunk/django/db/models/options.py    2012-02-22 00:52:19 UTC (rev 
17572)
+++ django/trunk/django/db/models/options.py    2012-02-22 05:26:50 UTC (rev 
17573)
@@ -40,7 +40,16 @@
         self.abstract = False
         self.managed = True
         self.proxy = False
+        # For any class which is a proxy (including automatically created
+        # classes for deferred object loading) the proxy_for_model tells
+        # which class this model is proxying. Note that proxy_for_model
+        # can create a chain of proxy models. For non-proxy models the
+        # variable is always None.
         self.proxy_for_model = None
+        # For any non-abstract class the concrete class is the model
+        # in the end of the proxy_for_model chain. In particular, for
+        # concrete models the concrete_model is always the class itself.
+        self.concrete_model = None
         self.parents = SortedDict()
         self.duplicate_targets = {}
         self.auto_created = False

Modified: django/trunk/django/db/models/sql/compiler.py
===================================================================
--- django/trunk/django/db/models/sql/compiler.py       2012-02-22 00:52:19 UTC 
(rev 17572)
+++ django/trunk/django/db/models/sql/compiler.py       2012-02-22 05:26:50 UTC 
(rev 17573)
@@ -7,7 +7,7 @@
 from django.db.models.sql.constants import *
 from django.db.models.sql.datastructures import EmptyResultSet
 from django.db.models.sql.expressions import SQLEvaluator
-from django.db.models.sql.query import get_proxied_model, get_order_dir, Query
+from django.db.models.sql.query import get_order_dir, Query
 from django.db.utils import DatabaseError
 
 
@@ -266,7 +266,7 @@
         aliases = set()
         only_load = self.deferred_to_columns()
         # Skip all proxy to the root proxied model
-        proxied_model = get_proxied_model(opts)
+        proxied_model = opts.concrete_model
 
         if start_alias:
             seen = {None: start_alias}

Modified: django/trunk/django/db/models/sql/query.py
===================================================================
--- django/trunk/django/db/models/sql/query.py  2012-02-22 00:52:19 UTC (rev 
17572)
+++ django/trunk/django/db/models/sql/query.py  2012-02-22 05:26:50 UTC (rev 
17573)
@@ -575,10 +575,7 @@
             return
         orig_opts = self.model._meta
         seen = {}
-        if orig_opts.proxy:
-            must_include = {orig_opts.proxy_for_model: set([orig_opts.pk])}
-        else:
-            must_include = {self.model: set([orig_opts.pk])}
+        must_include = {orig_opts.concrete_model: set([orig_opts.pk])}
         for field_name in field_names:
             parts = field_name.split(LOOKUP_SEP)
             cur_model = self.model
@@ -586,7 +583,7 @@
             for name in parts[:-1]:
                 old_model = cur_model
                 source = opts.get_field_by_name(name)[0]
-                cur_model = opts.get_field_by_name(name)[0].rel.to
+                cur_model = source.rel.to
                 opts = cur_model._meta
                 # Even if we're "just passing through" this model, we must add
                 # both the current model's pk and the related reference field
@@ -946,7 +943,7 @@
         seen = {None: root_alias}
 
         # Skip all proxy to the root proxied model
-        proxied_model = get_proxied_model(opts)
+        proxied_model = opts.concrete_model
 
         for field, model in opts.get_fields_with_model():
             if model not in seen:
@@ -1325,7 +1322,7 @@
             if model:
                 # The field lives on a base class of the current model.
                 # Skip the chain of proxy to the concrete proxied model
-                proxied_model = get_proxied_model(opts)
+                proxied_model = opts.concrete_model
 
                 for int_model in opts.get_base_chain(model):
                     if int_model is proxied_model:
@@ -1990,11 +1987,3 @@
         data[key].add(value)
     else:
         data[key] = set([value])
-
-def get_proxied_model(opts):
-    int_opts = opts
-    proxied_model = None
-    while int_opts.proxy:
-        proxied_model = int_opts.proxy_for_model
-        int_opts = proxied_model._meta
-    return proxied_model

Modified: django/trunk/tests/modeltests/proxy_models/tests.py
===================================================================
--- django/trunk/tests/modeltests/proxy_models/tests.py 2012-02-22 00:52:19 UTC 
(rev 17572)
+++ django/trunk/tests/modeltests/proxy_models/tests.py 2012-02-22 05:26:50 UTC 
(rev 17573)
@@ -232,6 +232,12 @@
         resp = [u.name for u in UserProxyProxy.objects.all()]
         self.assertEqual(resp, ['Bruce'])
 
+    def test_proxy_for_model(self):
+        self.assertEqual(UserProxy, UserProxyProxy._meta.proxy_for_model)
+
+    def test_concrete_model(self):
+        self.assertEqual(User, UserProxyProxy._meta.concrete_model)
+
     def test_proxy_delete(self):
         """
         Proxy objects can be deleted

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to