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 |