diff --git a/polymorphic/base.py b/polymorphic/base.py index 334f542..a7db9b1 100644 --- a/polymorphic/base.py +++ b/polymorphic/base.py @@ -16,6 +16,11 @@ from query import PolymorphicQuerySet # These are forbidden as field names (a descriptive exception is raised) POLYMORPHIC_SPECIAL_Q_KWORDS = ['instance_of', 'not_instance_of'] +try: + from django.db.models.manager import AbstractManagerDescriptor # Django 1.5 +except ImportError: + AbstractManagerDescriptor = None + ################################################################################### ### PolymorphicModel meta class @@ -91,6 +96,7 @@ class PolymorphicModelBase(ModelBase): 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:]: @@ -102,9 +108,23 @@ class PolymorphicModelBase(ModelBase): 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 in ['_base_manager']: + if key == '_base_manager': continue # let Django handle _base_manager if key in attrs: continue @@ -112,7 +132,8 @@ class PolymorphicModelBase(ModelBase): 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 >>sys.stderr,'##',self.__name__, key + #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)) @@ -121,16 +142,18 @@ class PolymorphicModelBase(ModelBase): @classmethod def get_first_user_defined_manager(self): + # See if there is a manager attribute directly stored at this inheritance level. mgr_list = [] for key, val in self.__dict__.items(): item = getattr(self, key) if not isinstance(item, models.Manager): continue mgr_list.append((item.creation_counter, key, item)) + # 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=model_name, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) ) + # .format( model=self.__name__, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) ) return manager return None diff --git a/polymorphic/polymorphic_model.py b/polymorphic/polymorphic_model.py index 76cecf9..baf986c 100644 --- a/polymorphic/polymorphic_model.py +++ b/polymorphic/polymorphic_model.py @@ -67,6 +67,8 @@ class PolymorphicModel(models.Model): # some applications want to know the name of the fields that are added to its models polymorphic_internal_model_fields = ['polymorphic_ctype'] + # Note that Django 1.5 removes these managers because the model is abstract. + # They are pretended to be there by the metaclass in PolymorphicModelBase.get_inherited_managers() objects = PolymorphicManager() base_objects = models.Manager()