Merge branch 'django110'
commit
cf1d4b532d
|
|
@ -15,6 +15,7 @@ env:
|
||||||
- DJANGO="Django>=1.7,<1.8"
|
- DJANGO="Django>=1.7,<1.8"
|
||||||
- DJANGO="Django>=1.8,<1.9"
|
- DJANGO="Django>=1.8,<1.9"
|
||||||
- DJANGO="Django>=1.9,<1.10"
|
- DJANGO="Django>=1.9,<1.10"
|
||||||
|
- DJANGO="Django>=1.10,<1.11"
|
||||||
- DJANGO="https://github.com/django/django/tarball/master"
|
- DJANGO="https://github.com/django/django/tarball/master"
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -32,16 +33,22 @@ matrix:
|
||||||
env: DJANGO="Django>=1.4,<1.5"
|
env: DJANGO="Django>=1.4,<1.5"
|
||||||
- python: "3.4"
|
- python: "3.4"
|
||||||
env: DJANGO="Django>=1.9,<1.10"
|
env: DJANGO="Django>=1.9,<1.10"
|
||||||
|
- python: "3.4"
|
||||||
|
env: DJANGO="Django>=1.10,<1.11"
|
||||||
|
|
||||||
- python: "3.3"
|
- python: "3.3"
|
||||||
env: DJANGO="Django>=1.4,<1.5"
|
env: DJANGO="Django>=1.4,<1.5"
|
||||||
- python: "3.3"
|
- python: "3.3"
|
||||||
env: DJANGO="Django>=1.9,<1.10"
|
env: DJANGO="Django>=1.9,<1.10"
|
||||||
|
- python: "3.3"
|
||||||
|
env: DJANGO="Django>=1.10,<1.11"
|
||||||
|
|
||||||
- python: "3.2"
|
- python: "3.2"
|
||||||
env: DJANGO="Django>=1.4,<1.5"
|
env: DJANGO="Django>=1.4,<1.5"
|
||||||
- python: "3.2"
|
- python: "3.2"
|
||||||
env: DJANGO="Django>=1.9,<1.10"
|
env: DJANGO="Django>=1.9,<1.10"
|
||||||
|
- python: "3.2"
|
||||||
|
env: DJANGO="Django>=1.10,<1.11"
|
||||||
|
|
||||||
- python: "2.6"
|
- python: "2.6"
|
||||||
env: DJANGO="Django>=1.7,<1.8"
|
env: DJANGO="Django>=1.7,<1.8"
|
||||||
|
|
@ -49,6 +56,8 @@ matrix:
|
||||||
env: DJANGO="Django>=1.8,<1.9"
|
env: DJANGO="Django>=1.8,<1.9"
|
||||||
- python: "2.6"
|
- python: "2.6"
|
||||||
env: DJANGO="Django>=1.9,<1.10"
|
env: DJANGO="Django>=1.9,<1.10"
|
||||||
|
- python: "2.6"
|
||||||
|
env: DJANGO="Django>=1.10,<1.11"
|
||||||
- python: "2.6"
|
- python: "2.6"
|
||||||
env: DJANGO="https://github.com/django/django/tarball/master"
|
env: DJANGO="https://github.com/django/django/tarball/master"
|
||||||
allow_failures:
|
allow_failures:
|
||||||
|
|
|
||||||
|
|
@ -71,24 +71,25 @@ class PolymorphicModelBase(ModelBase):
|
||||||
self.validate_model_fields(new_class)
|
self.validate_model_fields(new_class)
|
||||||
|
|
||||||
# create list of all managers to be inherited from the base classes
|
# 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
|
# add the managers to the new model
|
||||||
for source_name, mgr_name, manager in inherited_managers:
|
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__)
|
# 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)
|
new_manager = manager._copy_to_model(new_class)
|
||||||
if mgr_name == '_default_manager':
|
if mgr_name == '_default_manager':
|
||||||
new_class._default_manager = new_manager
|
new_class._default_manager = new_manager
|
||||||
else:
|
else:
|
||||||
new_class.add_to_class(mgr_name, new_manager)
|
new_class.add_to_class(mgr_name, new_manager)
|
||||||
|
|
||||||
# get first user defined manager; if there is one, make it the _default_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.
|
# 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)
|
user_manager = self.get_first_user_defined_manager(new_class)
|
||||||
if user_manager:
|
if user_manager:
|
||||||
# print '## add default manager', type(def_mgr)
|
# print '## add default manager', type(def_mgr)
|
||||||
new_class._default_manager = user_manager._copy_to_model(new_class)
|
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
|
new_class._default_manager._inherited = False # the default mgr was defined by the user, not inherited
|
||||||
|
|
||||||
# validate resulting default manager
|
# validate resulting default manager
|
||||||
self.validate_model_manager(new_class._default_manager, model_name, '_default_manager')
|
self.validate_model_manager(new_class._default_manager, model_name, '_default_manager')
|
||||||
|
|
@ -105,80 +106,81 @@ class PolymorphicModelBase(ModelBase):
|
||||||
|
|
||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
def get_inherited_managers(self, attrs):
|
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),
|
Return list of all managers to be inherited/propagated from the base classes;
|
||||||
skip managers that are overwritten by the user with same-named class attributes (in attrs)
|
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 = []
|
# print "** ", self.__name__
|
||||||
add_managers_keys = set()
|
add_managers = []
|
||||||
for base in self.__mro__[1:]:
|
add_managers_keys = set()
|
||||||
if not issubclass(base, models.Model):
|
for base in self.__mro__[1:]:
|
||||||
continue
|
if not issubclass(base, models.Model):
|
||||||
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
|
continue
|
||||||
if key == '_base_manager':
|
if not getattr(base, 'polymorphic_model_marker', None):
|
||||||
continue # let Django handle _base_manager
|
continue # leave managers of non-polym. models alone
|
||||||
if key in attrs:
|
|
||||||
|
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
|
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
|
mgr_list.append((val.creation_counter, key, val))
|
||||||
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.
|
# if there are user defined managers, use first one as _default_manager
|
||||||
# Make sure base_objects is on top, and 'objects' and '_default_manager' follow afterwards.
|
if mgr_list:
|
||||||
# This makes sure that the _base_manager is also assigned properly.
|
_, manager_name, manager = sorted(mgr_list)[0]
|
||||||
add_managers = sorted(add_managers, key=lambda item: (item[1].startswith('_'), item[1]))
|
# sys.stderr.write( '\n# first user defined manager for model "{model}":\n# "{mgrname}": {mgr}\n# manager model: {mgrmodel}\n\n'
|
||||||
return add_managers
|
# .format( model=self.__name__, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) )
|
||||||
|
return manager
|
||||||
@classmethod
|
return None
|
||||||
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
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def call_superclass_new_method(self, model_name, bases, attrs):
|
def call_superclass_new_method(self, model_name, bases, attrs):
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import copy
|
||||||
import django
|
import django
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.contenttypes.models import ContentType
|
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
|
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]
|
q_objects = [q.clone() for q in args]
|
||||||
else:
|
else:
|
||||||
q_objects = args # NOTE: edits existing objects in place.
|
q_objects = args # NOTE: edits existing objects in place.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,18 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import django
|
||||||
|
import re
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
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
|
||||||
class ShowFieldBase(object):
|
class ShowFieldBase(object):
|
||||||
""" base class for the ShowField... model mixins, does the work """
|
""" base class for the ShowField... model mixins, does the work """
|
||||||
|
|
||||||
|
|
@ -11,6 +20,7 @@ class ShowFieldBase(object):
|
||||||
|
|
||||||
polymorphic_showfield_type = False
|
polymorphic_showfield_type = False
|
||||||
polymorphic_showfield_content = False
|
polymorphic_showfield_content = False
|
||||||
|
polymorphic_showfield_deferred = False
|
||||||
|
|
||||||
# these may be overridden by the user
|
# these may be overridden by the user
|
||||||
polymorphic_showfield_max_line_width = None
|
polymorphic_showfield_max_line_width = None
|
||||||
|
|
@ -87,12 +97,12 @@ class ShowFieldBase(object):
|
||||||
|
|
||||||
parts.append((False, out, ','))
|
parts.append((False, out, ','))
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
# create list ("parts") containing one tuple for each title/field:
|
# create list ("parts") containing one tuple for each title/field:
|
||||||
# ( bool: new section , item-text , separator to use after item )
|
# ( bool: new section , item-text , separator to use after item )
|
||||||
|
|
||||||
# start with model name
|
# start with model name
|
||||||
parts = [(True, self.__class__.__name__, ':')]
|
parts = [(True, RE_DEFERRED.sub('', self.__class__.__name__), ':')]
|
||||||
|
|
||||||
# add all regular fields
|
# add all regular fields
|
||||||
self._showfields_add_regular_fields(parts)
|
self._showfields_add_regular_fields(parts)
|
||||||
|
|
@ -105,6 +115,11 @@ class ShowFieldBase(object):
|
||||||
if hasattr(self, 'polymorphic_extra_select_names'):
|
if hasattr(self, 'polymorphic_extra_select_names'):
|
||||||
self._showfields_add_dynamic_fields(self.polymorphic_extra_select_names, 'Extra', parts)
|
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
|
# format result
|
||||||
|
|
||||||
indent = len(self.__class__.__name__) + 5
|
indent = len(self.__class__.__name__) + 5
|
||||||
|
|
@ -142,6 +157,11 @@ class ShowFieldBase(object):
|
||||||
|
|
||||||
return '<' + out + '>'
|
return '<' + out + '>'
|
||||||
|
|
||||||
|
if django.VERSION < (1, 8):
|
||||||
|
def get_deferred_fields(self):
|
||||||
|
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):
|
class ShowFieldType(ShowFieldBase):
|
||||||
""" model mixin that shows the object's class and it's field types """
|
""" model mixin that shows the object's class and it's field types """
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ class PlainC(PlainB):
|
||||||
|
|
||||||
class Model2A(ShowFieldType, PolymorphicModel):
|
class Model2A(ShowFieldType, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
polymorphic_showfield_deferred = True
|
||||||
|
|
||||||
|
|
||||||
class Model2B(Model2A):
|
class Model2B(Model2A):
|
||||||
|
|
@ -562,36 +563,36 @@ class PolymorphicTests(TestCase):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
objects_deferred = Model2A.objects.defer('field1')
|
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[0]),
|
||||||
'<Model2A_Deferred_field1: id 1, field1 (CharField)>')
|
'<Model2A: id 1, field1 (CharField), deferred[field1]>')
|
||||||
self.assertEqual(repr(objects_deferred[1]),
|
self.assertEqual(repr(objects_deferred[1]),
|
||||||
'<Model2B_Deferred_field1: id 2, field1 (CharField), field2 (CharField)>')
|
'<Model2B: id 2, field1 (CharField), field2 (CharField), deferred[field1]>')
|
||||||
self.assertEqual(repr(objects_deferred[2]),
|
self.assertEqual(repr(objects_deferred[2]),
|
||||||
'<Model2C_Deferred_field1: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField), deferred[field1]>')
|
||||||
self.assertEqual(repr(objects_deferred[3]),
|
self.assertEqual(repr(objects_deferred[3]),
|
||||||
'<Model2D_Deferred_field1: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), deferred[field1]>')
|
||||||
|
|
||||||
objects_only = Model2A.objects.only('pk', 'polymorphic_ctype', 'field1')
|
objects_only = Model2A.objects.only('pk', 'polymorphic_ctype', 'field1')
|
||||||
|
|
||||||
self.assertIn('field1', objects_only[0].__dict__,
|
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__,
|
self.assertIn('field1', objects_only[3].__dict__,
|
||||||
'qs.only("field1") was used, but field1 was incorrectly deferred'
|
'qs.only("field1") was used, but field1 was incorrectly deferred'
|
||||||
' on a child model')
|
' on a child model')
|
||||||
self.assertNotIn('field4', objects_only[3].__dict__,
|
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[0]),
|
||||||
'<Model2A: id 1, field1 (CharField)>')
|
'<Model2A: id 1, field1 (CharField)>')
|
||||||
self.assertEqual(repr(objects_only[1]),
|
self.assertEqual(repr(objects_only[1]),
|
||||||
'<Model2B_Deferred_field2: '
|
'<Model2B: id 2, field1 (CharField), field2 (CharField), deferred[field2]>')
|
||||||
'id 2, field1 (CharField), field2 (CharField)>')
|
|
||||||
self.assertEqual(repr(objects_only[2]),
|
self.assertEqual(repr(objects_only[2]),
|
||||||
'<Model2C_Deferred_field2_field3_model2a_ptr_id: '
|
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField), '
|
||||||
'id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
'deferred[field2,field3,model2a_ptr_id]>')
|
||||||
self.assertEqual(repr(objects_only[3]),
|
self.assertEqual(repr(objects_only[3]),
|
||||||
'<Model2D_Deferred_field2_field3_field4_model2a_ptr_id_model2b_ptr_id: '
|
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), '
|
||||||
'id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
'deferred[field2,field3,field4,model2a_ptr_id,model2b_ptr_id]>')
|
||||||
|
|
||||||
# A bug in Django 1.4 prevents using defer across reverse relations
|
# A bug in Django 1.4 prevents using defer across reverse relations
|
||||||
# <https://code.djangoproject.com/ticket/14694>. Since polymorphic
|
# <https://code.djangoproject.com/ticket/14694>. Since polymorphic
|
||||||
|
|
@ -603,15 +604,15 @@ class PolymorphicTests(TestCase):
|
||||||
|
|
||||||
objects_deferred_field4 = Model2A.objects.defer('Model2D___field4')
|
objects_deferred_field4 = Model2A.objects.defer('Model2D___field4')
|
||||||
self.assertNotIn('field4', objects_deferred_field4[3].__dict__,
|
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[0]),
|
||||||
'<Model2A: id 1, field1 (CharField)>')
|
'<Model2A: id 1, field1 (CharField)>')
|
||||||
self.assertEqual(repr(objects_deferred_field4[1]),
|
self.assertEqual(repr(objects_deferred_field4[1]),
|
||||||
'<Model2B: id 2, field1 (CharField), field2 (CharField)>')
|
'<Model2B: id 2, field1 (CharField), field2 (CharField)>')
|
||||||
self.assertEqual(repr(objects_deferred_field4[2]),
|
self.assertEqual(repr(objects_deferred_field4[2]),
|
||||||
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
self.assertEqual(repr(objects_deferred_field4[3]),
|
self.assertEqual(repr(objects_deferred_field4[3]),
|
||||||
'<Model2D_Deferred_field4: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), deferred[field4]>')
|
||||||
|
|
||||||
objects_only_field4 = Model2A.objects.only(
|
objects_only_field4 = Model2A.objects.only(
|
||||||
'polymorphic_ctype', 'field1',
|
'polymorphic_ctype', 'field1',
|
||||||
|
|
@ -619,13 +620,13 @@ class PolymorphicTests(TestCase):
|
||||||
'Model2C___id', 'Model2C___field3', 'Model2C___model2b_ptr',
|
'Model2C___id', 'Model2C___field3', 'Model2C___model2b_ptr',
|
||||||
'Model2D___id', 'Model2D___model2c_ptr')
|
'Model2D___id', 'Model2D___model2c_ptr')
|
||||||
self.assertEqual(repr(objects_only_field4[0]),
|
self.assertEqual(repr(objects_only_field4[0]),
|
||||||
'<Model2A: id 1, field1 (CharField)>')
|
'<Model2A: id 1, field1 (CharField)>')
|
||||||
self.assertEqual(repr(objects_only_field4[1]),
|
self.assertEqual(repr(objects_only_field4[1]),
|
||||||
'<Model2B: id 2, field1 (CharField), field2 (CharField)>')
|
'<Model2B: id 2, field1 (CharField), field2 (CharField)>')
|
||||||
self.assertEqual(repr(objects_only_field4[2]),
|
self.assertEqual(repr(objects_only_field4[2]),
|
||||||
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
'<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
self.assertEqual(repr(objects_only_field4[3]),
|
self.assertEqual(repr(objects_only_field4[3]),
|
||||||
'<Model2D_Deferred_field4: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), deferred[field4]>')
|
||||||
|
|
||||||
|
|
||||||
def test_manual_get_real_instance(self):
|
def test_manual_get_real_instance(self):
|
||||||
|
|
@ -681,17 +682,26 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(show_base_manager(PlainC), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>")
|
self.assertEqual(show_base_manager(PlainC), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>")
|
||||||
|
|
||||||
self.assertEqual(show_base_manager(Model2A), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
|
self.assertEqual(show_base_manager(Model2A), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
|
||||||
self.assertEqual(show_base_manager(Model2B), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2B'>")
|
if django.VERSION >= (1, 10):
|
||||||
self.assertEqual(show_base_manager(Model2C), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2C'>")
|
# The new inheritance makes all model levels polymorphic
|
||||||
|
self.assertEqual(show_base_manager(Model2B), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2B'>")
|
||||||
|
self.assertEqual(show_base_manager(Model2C), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2C'>")
|
||||||
|
else:
|
||||||
|
self.assertEqual(show_base_manager(Model2B), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2B'>")
|
||||||
|
self.assertEqual(show_base_manager(Model2C), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2C'>")
|
||||||
|
|
||||||
self.assertEqual(show_base_manager(One2OneRelatingModel), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModel'>")
|
self.assertEqual(show_base_manager(One2OneRelatingModel), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModel'>")
|
||||||
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
|
if django.VERSION >= (1, 10):
|
||||||
|
# The new inheritance makes all model levels polymorphic
|
||||||
|
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
|
||||||
|
else:
|
||||||
|
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
|
||||||
|
|
||||||
def test_instance_default_manager(self):
|
def test_instance_default_manager(self):
|
||||||
def show_default_manager(instance):
|
def show_default_manager(instance):
|
||||||
return "{0} {1}".format(
|
return "{0} {1}".format(
|
||||||
repr(type(instance._default_manager)),
|
repr(type(instance.__class__._default_manager)),
|
||||||
repr(instance._default_manager.model)
|
repr(instance.__class__._default_manager.model)
|
||||||
)
|
)
|
||||||
|
|
||||||
plain_a = PlainA(field1='C1')
|
plain_a = PlainA(field1='C1')
|
||||||
|
|
@ -757,7 +767,7 @@ class PolymorphicTests(TestCase):
|
||||||
# no pretty printing
|
# no pretty printing
|
||||||
ModelShow1_plain.objects.create(field1='abc')
|
ModelShow1_plain.objects.create(field1='abc')
|
||||||
ModelShow2_plain.objects.create(field1='abc', field2='def')
|
ModelShow2_plain.objects.create(field1='abc', field2='def')
|
||||||
self.assertEqual(repr(ModelShow1_plain.objects.all()), '[<ModelShow1_plain: ModelShow1_plain object>, <ModelShow2_plain: ModelShow2_plain object>]')
|
self.assertEqual(qrepr(ModelShow1_plain.objects.all()), '<QuerySet [<ModelShow1_plain: ModelShow1_plain object>, <ModelShow2_plain: ModelShow2_plain object>]>')
|
||||||
|
|
||||||
def test_extra_method(self):
|
def test_extra_method(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
@ -1138,10 +1148,11 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(result, {'cnt': 2})
|
self.assertEqual(result, {'cnt': 2})
|
||||||
|
|
||||||
# aggregate using **args
|
# aggregate using **args
|
||||||
with self.assertRaisesMessage(AssertionError, 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'):
|
self.assertRaisesMessage(
|
||||||
Model2A.objects.aggregate(Count('Model2B___field2'))
|
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")
|
@skipIf(django.VERSION < (1,8,), "This test needs Django >=1.8")
|
||||||
def test_polymorphic__complex_aggregate(self):
|
def test_polymorphic__complex_aggregate(self):
|
||||||
|
|
@ -1172,11 +1183,10 @@ class PolymorphicTests(TestCase):
|
||||||
@skipIf(django.VERSION < (1,8,), "This test needs Django >=1.8")
|
@skipIf(django.VERSION < (1,8,), "This test needs Django >=1.8")
|
||||||
def test_polymorphic__expressions(self):
|
def test_polymorphic__expressions(self):
|
||||||
|
|
||||||
from django.db.models.expressions import DateTime
|
from django.db.models.functions import Concat
|
||||||
from django.utils.timezone import utc
|
|
||||||
|
|
||||||
# no exception raised
|
# no exception raised
|
||||||
result = DateModel.objects.annotate(val=DateTime('date', 'day', utc))
|
result = Model2B.objects.annotate(val=Concat('field1', 'field2'))
|
||||||
self.assertEqual(list(result), [])
|
self.assertEqual(list(result), [])
|
||||||
|
|
||||||
class RegressionTests(TestCase):
|
class RegressionTests(TestCase):
|
||||||
|
|
@ -1288,3 +1298,16 @@ class MultipleDatabasesTests(TestCase):
|
||||||
|
|
||||||
# Ensure no queries are made using the default database.
|
# Ensure no queries are made using the default database.
|
||||||
self.assertNumQueries(0, func)
|
self.assertNumQueries(0, func)
|
||||||
|
|
||||||
|
|
||||||
|
def qrepr(data):
|
||||||
|
"""
|
||||||
|
Ensure consistent repr() output for the QuerySet object.
|
||||||
|
"""
|
||||||
|
if isinstance(data, QuerySet):
|
||||||
|
if django.VERSION >= (1, 10):
|
||||||
|
return repr(data)
|
||||||
|
else:
|
||||||
|
return '<QuerySet %r>' % data
|
||||||
|
|
||||||
|
return repr(data)
|
||||||
|
|
|
||||||
7
tox.ini
7
tox.ini
|
|
@ -1,11 +1,11 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist=
|
envlist=
|
||||||
py26-django{14,15,16},
|
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},
|
py32-django{15,16,17,18},
|
||||||
py33-django{15,16,17,18},
|
py33-django{15,16,17,18},
|
||||||
py34-django{15,16,17,18,19},
|
py34-django{15,16,17,18,19,110},
|
||||||
py35-django{18,19}
|
py35-django{18,19,110}
|
||||||
# py33-django-dev,
|
# py33-django-dev,
|
||||||
docs,
|
docs,
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@ deps =
|
||||||
django17: Django >= 1.7, < 1.8
|
django17: Django >= 1.7, < 1.8
|
||||||
django18: Django >= 1.8, < 1.9
|
django18: Django >= 1.8, < 1.9
|
||||||
django19: Django >= 1.9, < 1.10
|
django19: Django >= 1.9, < 1.10
|
||||||
|
django110: Django >= 1.10, < 1.11
|
||||||
django-dev: https://github.com/django/django/tarball/master
|
django-dev: https://github.com/django/django/tarball/master
|
||||||
commands=
|
commands=
|
||||||
python runtests.py
|
python runtests.py
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue