From a5e348ffb94a3ed1549bbe83bbe1059a8218aafb Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Fri, 5 Aug 2016 17:21:18 +0200 Subject: [PATCH 1/9] Disable the old _default_manager and _copy_to_model() fiddling. This no longer works on Django 1.10, which has a new way to find the default manager --- polymorphic/base.py | 174 ++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 86 deletions(-) diff --git a/polymorphic/base.py b/polymorphic/base.py index 4ef8761..1c472b6 100644 --- a/polymorphic/base.py +++ b/polymorphic/base.py @@ -71,24 +71,25 @@ class PolymorphicModelBase(ModelBase): self.validate_model_fields(new_class) # create list of all managers to be inherited from the base classes - inherited_managers = new_class.get_inherited_managers(attrs) + if django.VERSION < (1, 10): + inherited_managers = new_class.get_inherited_managers(attrs) - # add the managers to the new model - for source_name, mgr_name, manager in inherited_managers: - # print '** add inherited manager from model %s, manager %s, %s' % (source_name, mgr_name, manager.__class__.__name__) - new_manager = manager._copy_to_model(new_class) - if mgr_name == '_default_manager': - new_class._default_manager = new_manager - else: - new_class.add_to_class(mgr_name, new_manager) + # add the managers to the new model + for source_name, mgr_name, manager in inherited_managers: + # print '** add inherited manager from model %s, manager %s, %s' % (source_name, mgr_name, manager.__class__.__name__) + new_manager = manager._copy_to_model(new_class) + if mgr_name == '_default_manager': + new_class._default_manager = new_manager + else: + new_class.add_to_class(mgr_name, new_manager) - # get first user defined manager; if there is one, make it the _default_manager - # this value is used by the related objects, restoring access to custom queryset methods on related objects. - user_manager = self.get_first_user_defined_manager(new_class) - if user_manager: - # print '## add default manager', type(def_mgr) - new_class._default_manager = user_manager._copy_to_model(new_class) - new_class._default_manager._inherited = False # the default mgr was defined by the user, not inherited + # get first user defined manager; if there is one, make it the _default_manager + # this value is used by the related objects, restoring access to custom queryset methods on related objects. + user_manager = self.get_first_user_defined_manager(new_class) + if user_manager: + # print '## add default manager', type(def_mgr) + new_class._default_manager = user_manager._copy_to_model(new_class) + new_class._default_manager._inherited = False # the default mgr was defined by the user, not inherited # validate resulting default manager self.validate_model_manager(new_class._default_manager, model_name, '_default_manager') @@ -105,80 +106,81 @@ class PolymorphicModelBase(ModelBase): return new_class - def get_inherited_managers(self, attrs): - """ - Return list of all managers to be inherited/propagated from the base classes; - use correct mro, only use managers with _inherited==False (they are of no use), - skip managers that are overwritten by the user with same-named class attributes (in attrs) - """ - # print "** ", self.__name__ - add_managers = [] - add_managers_keys = set() - for base in self.__mro__[1:]: - if not issubclass(base, models.Model): - continue - if not getattr(base, 'polymorphic_model_marker', None): - continue # leave managers of non-polym. models alone - - for key, manager in base.__dict__.items(): - if type(manager) == models.manager.ManagerDescriptor: - manager = manager.manager - - if AbstractManagerDescriptor is not None: - # Django 1.4 unconditionally assigned managers to a model. As of Django 1.5 however, - # the abstract models don't get any managers, only a AbstractManagerDescriptor as substitute. - # Pretend that the manager is still there, so all code works like it used to. - if type(manager) == AbstractManagerDescriptor and base.__name__ == 'PolymorphicModel': - model = manager.model - if key == 'objects': - manager = PolymorphicManager() - manager.model = model - elif key == 'base_objects': - manager = models.Manager() - manager.model = model - - if not isinstance(manager, models.Manager): + if django.VERSION < (1, 10): + def get_inherited_managers(self, attrs): + """ + Return list of all managers to be inherited/propagated from the base classes; + use correct mro, only use managers with _inherited==False (they are of no use), + skip managers that are overwritten by the user with same-named class attributes (in attrs) + """ + # print "** ", self.__name__ + add_managers = [] + add_managers_keys = set() + for base in self.__mro__[1:]: + if not issubclass(base, models.Model): continue - if key == '_base_manager': - continue # let Django handle _base_manager - if key in attrs: + if not getattr(base, 'polymorphic_model_marker', None): + continue # leave managers of non-polym. models alone + + for key, manager in base.__dict__.items(): + if type(manager) == models.manager.ManagerDescriptor: + manager = manager.manager + + if AbstractManagerDescriptor is not None: + # Django 1.4 unconditionally assigned managers to a model. As of Django 1.5 however, + # the abstract models don't get any managers, only a AbstractManagerDescriptor as substitute. + # Pretend that the manager is still there, so all code works like it used to. + if type(manager) == AbstractManagerDescriptor and base.__name__ == 'PolymorphicModel': + model = manager.model + if key == 'objects': + manager = PolymorphicManager() + manager.model = model + elif key == 'base_objects': + manager = models.Manager() + manager.model = model + + if not isinstance(manager, models.Manager): + continue + if key == '_base_manager': + continue # let Django handle _base_manager + if key in attrs: + continue + if key in add_managers_keys: + continue # manager with that name already added, skip + if manager._inherited: + continue # inherited managers (on the bases) have no significance, they are just copies + # print '## {0} {1}'.format(self.__name__, key) + + if isinstance(manager, PolymorphicManager): # validate any inherited polymorphic managers + self.validate_model_manager(manager, self.__name__, key) + add_managers.append((base.__name__, key, manager)) + add_managers_keys.add(key) + + # The ordering in the base.__dict__ may randomly change depending on which method is added. + # Make sure base_objects is on top, and 'objects' and '_default_manager' follow afterwards. + # This makes sure that the _base_manager is also assigned properly. + add_managers = sorted(add_managers, key=lambda item: (item[1].startswith('_'), item[1])) + return add_managers + + @classmethod + def get_first_user_defined_manager(mcs, new_class): + # See if there is a manager attribute directly stored at this inheritance level. + mgr_list = [] + for key, val in new_class.__dict__.items(): + if isinstance(val, ManagerDescriptor): + val = val.manager + if not isinstance(val, PolymorphicManager): continue - if key in add_managers_keys: - continue # manager with that name already added, skip - if manager._inherited: - continue # inherited managers (on the bases) have no significance, they are just copies - # print '## {0} {1}'.format(self.__name__, key) - if isinstance(manager, PolymorphicManager): # validate any inherited polymorphic managers - self.validate_model_manager(manager, self.__name__, key) - add_managers.append((base.__name__, key, manager)) - add_managers_keys.add(key) + mgr_list.append((val.creation_counter, key, val)) - # The ordering in the base.__dict__ may randomly change depending on which method is added. - # Make sure base_objects is on top, and 'objects' and '_default_manager' follow afterwards. - # This makes sure that the _base_manager is also assigned properly. - add_managers = sorted(add_managers, key=lambda item: (item[1].startswith('_'), item[1])) - return add_managers - - @classmethod - def get_first_user_defined_manager(mcs, new_class): - # See if there is a manager attribute directly stored at this inheritance level. - mgr_list = [] - for key, val in new_class.__dict__.items(): - if isinstance(val, ManagerDescriptor): - val = val.manager - if not isinstance(val, PolymorphicManager): - continue - - mgr_list.append((val.creation_counter, key, val)) - - # if there are user defined managers, use first one as _default_manager - if mgr_list: - _, manager_name, manager = sorted(mgr_list)[0] - # sys.stderr.write( '\n# first user defined manager for model "{model}":\n# "{mgrname}": {mgr}\n# manager model: {mgrmodel}\n\n' - # .format( model=self.__name__, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) ) - return manager - return None + # if there are user defined managers, use first one as _default_manager + if mgr_list: + _, manager_name, manager = sorted(mgr_list)[0] + # sys.stderr.write( '\n# first user defined manager for model "{model}":\n# "{mgrname}": {mgr}\n# manager model: {mgrmodel}\n\n' + # .format( model=self.__name__, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) ) + return manager + return None @classmethod def call_superclass_new_method(self, model_name, bases, attrs): From 1a998733e19ee8b12aef9ae0635af281e71de973 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Fri, 5 Aug 2016 17:21:53 +0200 Subject: [PATCH 2/9] Fix QuerySte repr output for Django 1.10 in unit tests --- polymorphic/tests.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/polymorphic/tests.py b/polymorphic/tests.py index 8c5cf2e..9ff5892 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -757,7 +757,7 @@ class PolymorphicTests(TestCase): # no pretty printing ModelShow1_plain.objects.create(field1='abc') ModelShow2_plain.objects.create(field1='abc', field2='def') - self.assertEqual(repr(ModelShow1_plain.objects.all()), '[, ]') + self.assertEqual(qrepr(ModelShow1_plain.objects.all()), ', ]>') def test_extra_method(self): self.create_model2abcd() @@ -1288,3 +1288,16 @@ class MultipleDatabasesTests(TestCase): # Ensure no queries are made using the default database. self.assertNumQueries(0, func) + + +def qrepr(data): + """ + Ensure consistent repr() output for the QuerySet object. + """ + if isinstance(data, models.QuerySet): + if django.VERSION >= (1, 10): + return repr(data) + else: + return '' % data + + return repr(data) From 16586f398ccd667707a327ecafd4564ab1fcb704 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Fri, 5 Aug 2016 17:23:28 +0200 Subject: [PATCH 3/9] Update tox and travis settings for Django 1.10 --- .travis.yml | 9 +++++++++ tox.ini | 7 ++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 620b0d2..63cad33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ env: - DJANGO="Django>=1.7,<1.8" - DJANGO="Django>=1.8,<1.9" - DJANGO="Django>=1.9,<1.10" + - DJANGO="Django>=1.10,<1.11" - DJANGO="https://github.com/django/django/tarball/master" matrix: @@ -32,16 +33,22 @@ matrix: env: DJANGO="Django>=1.4,<1.5" - python: "3.4" env: DJANGO="Django>=1.9,<1.10" + - python: "3.4" + env: DJANGO="Django>=1.10,<1.11" - python: "3.3" env: DJANGO="Django>=1.4,<1.5" - python: "3.3" env: DJANGO="Django>=1.9,<1.10" + - python: "3.3" + env: DJANGO="Django>=1.10,<1.11" - python: "3.2" env: DJANGO="Django>=1.4,<1.5" - python: "3.2" env: DJANGO="Django>=1.9,<1.10" + - python: "3.2" + env: DJANGO="Django>=1.10,<1.11" - python: "2.6" env: DJANGO="Django>=1.7,<1.8" @@ -49,6 +56,8 @@ matrix: env: DJANGO="Django>=1.8,<1.9" - python: "2.6" env: DJANGO="Django>=1.9,<1.10" + - python: "2.6" + env: DJANGO="Django>=1.10,<1.11" - python: "2.6" env: DJANGO="https://github.com/django/django/tarball/master" allow_failures: diff --git a/tox.ini b/tox.ini index 2a62813..6a3af4e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,11 @@ [tox] envlist= py26-django{14,15,16}, - py27-django{14,15,16,17,18,19}, + py27-django{14,15,16,17,18,19,110}, py32-django{15,16,17,18}, py33-django{15,16,17,18}, - py34-django{15,16,17,18,19}, - py35-django{18,19} + py34-django{15,16,17,18,19,110}, + py35-django{18,19,110} # py33-django-dev, docs, @@ -17,6 +17,7 @@ deps = django17: Django >= 1.7, < 1.8 django18: Django >= 1.8, < 1.9 django19: Django >= 1.9, < 1.10 + django110: Django >= 1.10, < 1.11 django-dev: https://github.com/django/django/tarball/master commands= python runtests.py From 2e694fb2c688e00c5492a041e76411816d1bccfc Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Fri, 5 Aug 2016 17:26:13 +0200 Subject: [PATCH 4/9] Fix for removed `Q.clone()` method in Django 1.10 --- polymorphic/query_translate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/polymorphic/query_translate.py b/polymorphic/query_translate.py index 67f8c6b..ba26a9f 100644 --- a/polymorphic/query_translate.py +++ b/polymorphic/query_translate.py @@ -4,6 +4,7 @@ """ from __future__ import absolute_import +import copy import django from django.db import models from django.contrib.contenttypes.models import ContentType @@ -100,7 +101,9 @@ def translate_polymorphic_filter_definitions_in_args(queryset_model, args, using Returns: modified Q objects """ - if django.VERSION >= (1, 6): + if django.VERSION >= (1, 10): + q_objects = [copy.deepcopy(q) for q in args] + elif django.VERSION >= (1, 6): q_objects = [q.clone() for q in args] else: q_objects = args # NOTE: edits existing objects in place. From dd894586153ec0bd3817c32325e0bf4d03d66d79 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Wed, 10 Aug 2016 13:20:16 +0200 Subject: [PATCH 5/9] Fixed expressions unit test, DateTime refactored in Django 1.10 --- polymorphic/tests.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/polymorphic/tests.py b/polymorphic/tests.py index 9ff5892..3a89b89 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -690,8 +690,8 @@ class PolymorphicTests(TestCase): def test_instance_default_manager(self): def show_default_manager(instance): return "{0} {1}".format( - repr(type(instance._default_manager)), - repr(instance._default_manager.model) + repr(type(instance.__class__._default_manager)), + repr(instance.__class__._default_manager.model) ) plain_a = PlainA(field1='C1') @@ -1172,11 +1172,10 @@ class PolymorphicTests(TestCase): @skipIf(django.VERSION < (1,8,), "This test needs Django >=1.8") def test_polymorphic__expressions(self): - from django.db.models.expressions import DateTime - from django.utils.timezone import utc + from django.db.models.functions import Concat # no exception raised - result = DateModel.objects.annotate(val=DateTime('date', 'day', utc)) + result = Model2B.objects.annotate(val=Concat('field1', 'field2')) self.assertEqual(list(result), []) class RegressionTests(TestCase): From 381706146749ad7a977b4687f487f783e39345b3 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Wed, 10 Aug 2016 13:43:19 +0200 Subject: [PATCH 6/9] Fix unit tests for defer() / only() Added get_deferred_fields() to ShowFieldBase --- polymorphic/showfields.py | 19 ++++++++++++++++--- polymorphic/tests.py | 29 +++++++++++++++-------------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/polymorphic/showfields.py b/polymorphic/showfields.py index 6d1f6e1..fdb4bcf 100644 --- a/polymorphic/showfields.py +++ b/polymorphic/showfields.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- - +import django from django.db import models from django.utils import six +from django.utils.six import python_2_unicode_compatible +@python_2_unicode_compatible class ShowFieldBase(object): """ base class for the ShowField... model mixins, does the work """ @@ -11,6 +13,7 @@ class ShowFieldBase(object): polymorphic_showfield_type = False polymorphic_showfield_content = False + polymorphic_showfield_deferred = False # these may be overridden by the user polymorphic_showfield_max_line_width = None @@ -87,12 +90,12 @@ class ShowFieldBase(object): parts.append((False, out, ',')) - def __unicode__(self): + def __str__(self): # create list ("parts") containing one tuple for each title/field: # ( bool: new section , item-text , separator to use after item ) # start with model name - parts = [(True, self.__class__.__name__, ':')] + parts = [(True, self._meta.object_name, ':')] # add all regular fields self._showfields_add_regular_fields(parts) @@ -105,6 +108,11 @@ class ShowFieldBase(object): if hasattr(self, 'polymorphic_extra_select_names'): self._showfields_add_dynamic_fields(self.polymorphic_extra_select_names, 'Extra', parts) + if self.polymorphic_showfield_deferred: + fields = self.get_deferred_fields() + if fields: + parts.append((False, u"deferred[{0}]".format(",".join(sorted(fields))), '')) + # format result indent = len(self.__class__.__name__) + 5 @@ -142,6 +150,11 @@ class ShowFieldBase(object): return '<' + out + '>' + if django.VERSION < (1, 8): + def get_deferred_fields(self): + from django.db.models import DeferredAttribute + return set(attr for attr, value in self.__class__ if isinstance(value, DeferredAttribute)) + class ShowFieldType(ShowFieldBase): """ model mixin that shows the object's class and it's field types """ diff --git a/polymorphic/tests.py b/polymorphic/tests.py index 3a89b89..38ad70c 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -46,6 +46,7 @@ class PlainC(PlainB): class Model2A(ShowFieldType, PolymorphicModel): field1 = models.CharField(max_length=10) + polymorphic_showfield_deferred = True class Model2B(Model2A): @@ -562,18 +563,19 @@ class PolymorphicTests(TestCase): self.create_model2abcd() objects_deferred = Model2A.objects.defer('field1') - self.assertNotIn('field1', objects_deferred[0].__dict__, - 'field1 was not deferred (using defer())') + + self.assertNotIn('field1', objects_deferred[0].__dict__, 'field1 was not deferred (using defer())') self.assertEqual(repr(objects_deferred[0]), - '') + '') self.assertEqual(repr(objects_deferred[1]), - '') + '') self.assertEqual(repr(objects_deferred[2]), - '') + '') self.assertEqual(repr(objects_deferred[3]), - '') + '') objects_only = Model2A.objects.only('pk', 'polymorphic_ctype', 'field1') + self.assertIn('field1', objects_only[0].__dict__, 'qs.only("field1") was used, but field1 was incorrectly deferred') self.assertIn('field1', objects_only[3].__dict__, @@ -584,14 +586,13 @@ class PolymorphicTests(TestCase): self.assertEqual(repr(objects_only[0]), '') self.assertEqual(repr(objects_only[1]), - '') + '') self.assertEqual(repr(objects_only[2]), - '') + '') self.assertEqual(repr(objects_only[3]), - '') + '') # A bug in Django 1.4 prevents using defer across reverse relations # . Since polymorphic @@ -611,7 +612,7 @@ class PolymorphicTests(TestCase): self.assertEqual(repr(objects_deferred_field4[2]), '') self.assertEqual(repr(objects_deferred_field4[3]), - '') + '') objects_only_field4 = Model2A.objects.only( 'polymorphic_ctype', 'field1', @@ -625,7 +626,7 @@ class PolymorphicTests(TestCase): self.assertEqual(repr(objects_only_field4[2]), '') self.assertEqual(repr(objects_only_field4[3]), - '') + '') def test_manual_get_real_instance(self): From 10ab3ad14c71f04dcc50bd65ee09838a6a7e7819 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Wed, 10 Aug 2016 13:51:30 +0200 Subject: [PATCH 7/9] Fix compatibility with older Django versions --- polymorphic/showfields.py | 15 +++++++++++---- polymorphic/tests.py | 11 ++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/polymorphic/showfields.py b/polymorphic/showfields.py index fdb4bcf..a7270d5 100644 --- a/polymorphic/showfields.py +++ b/polymorphic/showfields.py @@ -1,8 +1,15 @@ # -*- coding: utf-8 -*- import django +import re from django.db import models from django.utils import six -from django.utils.six import python_2_unicode_compatible + +try: + from django.utils.six import python_2_unicode_compatible +except ImportError: + from django.utils.encoding import python_2_unicode_compatible # Django 1.5 + +RE_DEFERRED = re.compile('_Deferred_.*') @python_2_unicode_compatible @@ -95,7 +102,7 @@ class ShowFieldBase(object): # ( bool: new section , item-text , separator to use after item ) # start with model name - parts = [(True, self._meta.object_name, ':')] + parts = [(True, RE_DEFERRED.sub('', self.__class__.__name__), ':')] # add all regular fields self._showfields_add_regular_fields(parts) @@ -152,8 +159,8 @@ class ShowFieldBase(object): if django.VERSION < (1, 8): def get_deferred_fields(self): - from django.db.models import DeferredAttribute - return set(attr for attr, value in self.__class__ if isinstance(value, DeferredAttribute)) + from django.db.models.query_utils import DeferredAttribute + return set(attr for attr, value in self.__class__.__dict__.items() if isinstance(value, DeferredAttribute)) class ShowFieldType(ShowFieldBase): diff --git a/polymorphic/tests.py b/polymorphic/tests.py index 38ad70c..cfddd90 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -1139,10 +1139,11 @@ class PolymorphicTests(TestCase): self.assertEqual(result, {'cnt': 2}) # aggregate using **args - with self.assertRaisesMessage(AssertionError, 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'): - Model2A.objects.aggregate(Count('Model2B___field2')) - - + self.assertRaisesMessage( + AssertionError, + 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only', + lambda: Model2A.objects.aggregate(Count('Model2B___field2')) + ) @skipIf(django.VERSION < (1,8,), "This test needs Django >=1.8") def test_polymorphic__complex_aggregate(self): @@ -1294,7 +1295,7 @@ def qrepr(data): """ Ensure consistent repr() output for the QuerySet object. """ - if isinstance(data, models.QuerySet): + if isinstance(data, QuerySet): if django.VERSION >= (1, 10): return repr(data) else: From bb0e71ee8f47cde88e3902141e5863c5f9363300 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Wed, 10 Aug 2016 13:54:44 +0200 Subject: [PATCH 8/9] autopep8 by pycharm --- polymorphic/tests.py | 46 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/polymorphic/tests.py b/polymorphic/tests.py index cfddd90..ee165ed 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -566,33 +566,33 @@ class PolymorphicTests(TestCase): self.assertNotIn('field1', objects_deferred[0].__dict__, 'field1 was not deferred (using defer())') self.assertEqual(repr(objects_deferred[0]), - '') + '') self.assertEqual(repr(objects_deferred[1]), - '') + '') self.assertEqual(repr(objects_deferred[2]), - '') + '') self.assertEqual(repr(objects_deferred[3]), - '') + '') objects_only = Model2A.objects.only('pk', 'polymorphic_ctype', 'field1') self.assertIn('field1', objects_only[0].__dict__, - 'qs.only("field1") was used, but field1 was incorrectly deferred') + 'qs.only("field1") was used, but field1 was incorrectly deferred') self.assertIn('field1', objects_only[3].__dict__, - 'qs.only("field1") was used, but field1 was incorrectly deferred' - ' on a child model') + 'qs.only("field1") was used, but field1 was incorrectly deferred' + ' on a child model') self.assertNotIn('field4', objects_only[3].__dict__, - 'field4 was not deferred (using only())') + 'field4 was not deferred (using only())') self.assertEqual(repr(objects_only[0]), - '') + '') self.assertEqual(repr(objects_only[1]), - '') + '') self.assertEqual(repr(objects_only[2]), - '') + '') self.assertEqual(repr(objects_only[3]), - '') + '') # A bug in Django 1.4 prevents using defer across reverse relations # . Since polymorphic @@ -604,15 +604,15 @@ class PolymorphicTests(TestCase): objects_deferred_field4 = Model2A.objects.defer('Model2D___field4') self.assertNotIn('field4', objects_deferred_field4[3].__dict__, - 'field4 was not deferred (using defer(), traversing inheritance)') + 'field4 was not deferred (using defer(), traversing inheritance)') self.assertEqual(repr(objects_deferred_field4[0]), - '') + '') self.assertEqual(repr(objects_deferred_field4[1]), - '') + '') self.assertEqual(repr(objects_deferred_field4[2]), - '') + '') self.assertEqual(repr(objects_deferred_field4[3]), - '') + '') objects_only_field4 = Model2A.objects.only( 'polymorphic_ctype', 'field1', @@ -620,13 +620,13 @@ class PolymorphicTests(TestCase): 'Model2C___id', 'Model2C___field3', 'Model2C___model2b_ptr', 'Model2D___id', 'Model2D___model2c_ptr') self.assertEqual(repr(objects_only_field4[0]), - '') + '') self.assertEqual(repr(objects_only_field4[1]), - '') + '') self.assertEqual(repr(objects_only_field4[2]), - '') + '') self.assertEqual(repr(objects_only_field4[3]), - '') + '') def test_manual_get_real_instance(self): From b4a02e9c47c2623f77b7b3856b42bef9ba4bfc38 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Wed, 10 Aug 2016 13:54:56 +0200 Subject: [PATCH 9/9] Let last base_manager test allow different results in Django 1.10 This is after all, how Django 1.10's new base manager works. --- polymorphic/tests.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/polymorphic/tests.py b/polymorphic/tests.py index ee165ed..379e955 100644 --- a/polymorphic/tests.py +++ b/polymorphic/tests.py @@ -682,11 +682,20 @@ class PolymorphicTests(TestCase): self.assertEqual(show_base_manager(PlainC), " ") self.assertEqual(show_base_manager(Model2A), " ") - self.assertEqual(show_base_manager(Model2B), " ") - self.assertEqual(show_base_manager(Model2C), " ") + if django.VERSION >= (1, 10): + # The new inheritance makes all model levels polymorphic + self.assertEqual(show_base_manager(Model2B), " ") + self.assertEqual(show_base_manager(Model2C), " ") + else: + self.assertEqual(show_base_manager(Model2B), " ") + self.assertEqual(show_base_manager(Model2C), " ") self.assertEqual(show_base_manager(One2OneRelatingModel), " ") - self.assertEqual(show_base_manager(One2OneRelatingModelDerived), " ") + if django.VERSION >= (1, 10): + # The new inheritance makes all model levels polymorphic + self.assertEqual(show_base_manager(One2OneRelatingModelDerived), " ") + else: + self.assertEqual(show_base_manager(One2OneRelatingModelDerived), " ") def test_instance_default_manager(self): def show_default_manager(instance):