diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index 6d919b4..6e99632 100644
a
|
b
|
class ContentTypeManager(models.Manager):
|
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_class._meta |
25 | 21 | |
26 | 22 | def _get_from_cache(self, opts): |
27 | 23 | key = (opts.app_label, opts.object_name.lower()) |
diff --git a/django/db/models/base.py b/django/db/models/base.py
index ebd67be..1810abd 100644
a
|
b
|
class ModelBase(type):
|
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_class = base._meta.concrete_class |
| 127 | else: |
| 128 | new_class._meta.concrete_class = 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 |
… |
… |
class ModelBase(type):
|
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_class |
155 | 154 | if base in o2o_map: |
156 | 155 | field = o2o_map[base] |
157 | 156 | elif not is_proxy: |
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 0cd52a3..ba3685a 100644
a
|
b
|
class Options(object):
|
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_class = None |
44 | 53 | self.parents = SortedDict() |
45 | 54 | self.duplicate_targets = {} |
46 | 55 | self.auto_created = False |
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index a78df34..f7cac1e 100644
a
|
b
|
class Query(object):
|
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 | # NOTE: This does what the previous code did. Is this correct? The |
| 579 | # code below is a bit hard to grasp... |
| 580 | must_include = {orig_opts.concrete_class: set([orig_opts.pk])} |
582 | 581 | for field_name in field_names: |
583 | 582 | parts = field_name.split(LOOKUP_SEP) |
584 | 583 | cur_model = self.model |
… |
… |
class Query(object):
|
586 | 585 | for name in parts[:-1]: |
587 | 586 | old_model = cur_model |
588 | 587 | source = opts.get_field_by_name(name)[0] |
589 | | cur_model = opts.get_field_by_name(name)[0].rel.to |
| 588 | cur_model = source.rel.to |
590 | 589 | opts = cur_model._meta |
591 | 590 | # Even if we're "just passing through" this model, we must add |
592 | 591 | # both the current model's pk and the related reference field |
… |
… |
def add_to_dict(data, key, value):
|
1992 | 1991 | data[key] = set([value]) |
1993 | 1992 | |
1994 | 1993 | 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 |
| 1994 | return opts.concrete_class |
diff --git a/tests/modeltests/proxy_models/tests.py b/tests/modeltests/proxy_models/tests.py
index 3ec8465..15c5dc0 100644
a
|
b
|
class ProxyModelTests(TestCase):
|
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.assertEquals(UserProxy, UserProxyProxy._meta.proxy_for_model) |
| 237 | |
235 | 238 | def test_proxy_delete(self): |
236 | 239 | """ |
237 | 240 | Proxy objects can be deleted |