From 49f95cc0a0167e91fd0f6987428905911bff076c Mon Sep 17 00:00:00 2001 From: Akshesh Date: Mon, 28 Mar 2016 00:50:54 +0530 Subject: [PATCH] Fixed #11560 -- Allowed proxy model multiple-inheritance from the same concrete base model. --- django/db/models/base.py | 6 +++--- docs/releases/1.10.txt | 3 +++ docs/topics/db/models.txt | 8 +++++++- tests/proxy_models/models.py | 10 ++++++++++ tests/proxy_models/tests.py | 10 ++++++---- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/django/db/models/base.py b/django/db/models/base.py index 1f2f64fff25..977c5bc9898 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -177,10 +177,10 @@ class ModelBase(type): ) else: continue - if base is not None: - raise TypeError("Proxy model '%s' has more than one non-abstract model base class." % name) - else: + if base is None: base = parent + elif parent._meta.concrete_model is not base._meta.concrete_model: + raise TypeError("Proxy model '%s' has more than one non-abstract model base class." % name) if base is None: raise TypeError("Proxy model '%s' has no non-abstract model base class." % name) new_class._meta.setup_proxy(base) diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index eee19584f72..373e9744ca0 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -359,6 +359,9 @@ Models * Added the :class:`~django.db.models.functions.Cast` database function. +* A proxy model may now inherit multiple proxy models that share a common + non-abstract parent class. + Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index 89dccb39f17..507e4d74725 100644 --- a/docs/topics/db/models.txt +++ b/docs/topics/db/models.txt @@ -1230,7 +1230,13 @@ A proxy model must inherit from exactly one non-abstract model class. You can't inherit from multiple non-abstract models as the proxy model doesn't provide any connection between the rows in the different database tables. A proxy model can inherit from any number of abstract model classes, providing -they do *not* define any model fields. +they do *not* define any model fields. A proxy model may also inherit from any +number of proxy models that share a common non-abstract parent class. + +.. versionchanged:: 1.10 + + In earlier versions, a proxy model couldn't inherit more than one proxy + model that shared the same parent class. Proxy model managers ~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/proxy_models/models.py b/tests/proxy_models/models.py index 6c5f98ec145..cb3975d4ace 100644 --- a/tests/proxy_models/models.py +++ b/tests/proxy_models/models.py @@ -110,10 +110,20 @@ class UserProxy(User): proxy = True +class AnotherUserProxy(User): + class Meta: + proxy = True + + class UserProxyProxy(UserProxy): class Meta: proxy = True + +class MultiUserProxy(UserProxy, AnotherUserProxy): + class Meta: + proxy = True + # We can still use `select_related()` to include related models in our querysets. diff --git a/tests/proxy_models/tests.py b/tests/proxy_models/tests.py index 9c2eccb3e5c..20899c68d5b 100644 --- a/tests/proxy_models/tests.py +++ b/tests/proxy_models/tests.py @@ -13,9 +13,9 @@ from django.urls import reverse from .admin import admin as force_admin_model_registration # NOQA from .models import ( Abstract, BaseUser, Bug, Country, Improvement, Issue, LowerStatusPerson, - MyPerson, MyPersonProxy, OtherPerson, Person, ProxyBug, ProxyImprovement, - ProxyProxyBug, ProxyTrackerUser, State, StateProxy, StatusPerson, - TrackerUser, User, UserProxy, UserProxyProxy, + MultiUserProxy, MyPerson, MyPersonProxy, OtherPerson, Person, ProxyBug, + ProxyImprovement, ProxyProxyBug, ProxyTrackerUser, State, StateProxy, + StatusPerson, TrackerUser, User, UserProxy, UserProxyProxy, ) @@ -246,7 +246,7 @@ class ProxyModelTests(TestCase): ctype = ContentType.objects.get_for_model self.assertIs(ctype(Person), ctype(OtherPerson)) - def test_user_userproxy_userproxyproxy(self): + def test_user_proxy_models(self): User.objects.create(name='Bruce') resp = [u.name for u in User.objects.all()] @@ -258,6 +258,8 @@ class ProxyModelTests(TestCase): resp = [u.name for u in UserProxyProxy.objects.all()] self.assertEqual(resp, ['Bruce']) + self.assertEqual([u.name for u in MultiUserProxy.objects.all()], ['Bruce']) + def test_proxy_for_model(self): self.assertEqual(UserProxy, UserProxyProxy._meta.proxy_for_model)