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
fix_request_path_info
Diederik van der Boor 2016-08-05 17:21:18 +02:00
parent 3172b41cbb
commit a5e348ffb9
1 changed files with 88 additions and 86 deletions

View File

@ -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):