def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError, "register() expects a Django model class argument" if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases)-1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: tree_manager_attr = cls._mptt_meta.tree_manager_attr manager = getattr(cls, tree_manager_attr, None) if (not manager) or manager.model != cls: if not manager: manager = TreeManager() else: # manager.model might already be set if this is a proxy model # (in that case, we need to create a new manager, or _base_manager will be wrong) manager = manager.__class__() manager.contribute_to_class(cls, tree_manager_attr) manager.init_from_model(cls) setattr(cls, '_tree_manager', manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError, "register() expects a Django model class argument" if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) # For backwards compatibility with existing libraries, we copy the # _mptt_meta options into _meta. # This will be removed in 0.5. # All new code should use _mptt_meta rather than _meta for tree attributes. for attr in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr', 'parent_attr', 'tree_manager_attr', 'order_insertion_by'): setattr(cls._meta, attr, getattr(cls._mptt_meta, attr)) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases)-1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a custom tree manager if not abstract: manager = TreeManager(cls._mptt_meta) manager.contribute_to_class(cls, cls._mptt_meta.tree_manager_attr) setattr(cls, '_tree_manager', getattr(cls, cls._mptt_meta.tree_manager_attr)) return cls
def forwards(self, orm): cls = orm.Party cls._mptt_meta = MPTTOptions(left_attr="tree_left", level_attr="tree_level", right_attr="tree_right") tree_manager = TreeManager() tree_manager.contribute_to_class(cls, "_tree_manager") tree_manager.init_from_model(cls) tree_manager.rebuild()
def __new__(meta, class_name, bases, class_dict): """ Create subclasses of MPTTModel. This: - adds the MPTT fields to the class - adds a TreeManager to the model """ mptt_opts = class_dict.pop('MPTTMeta', None) class_dict['_mptt_meta'] = MPTTOptions(mptt_opts) cls = ModelBase.__new__(meta, class_name, bases, class_dict) # For backwards compatibility with existing libraries, we copy the # _mptt_meta options into _meta. # This will be removed in 0.5. # All new code should use _mptt_meta rather than _meta for tree attributes. for attr in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr', 'parent_attr', 'tree_manager_attr', 'order_insertion_by'): setattr(cls._meta, attr, getattr(cls._mptt_meta, attr)) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a custom tree manager manager = TreeManager(cls._mptt_meta) manager.contribute_to_class(cls, cls._mptt_meta.tree_manager_attr) setattr(cls, '_tree_manager', getattr(cls, cls._mptt_meta.tree_manager_attr)) # Set up signal receivers model_signals.post_init.connect(signals.post_init, sender=cls) model_signals.pre_save.connect(signals.pre_save, sender=cls) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError(_("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) # For backwards compatibility with existing libraries, we copy the # _mptt_meta options into _meta. # This was removed in 0.5 but added back in 0.5.1 since it caused compatibility # issues with django-cms 2.2.0. # some discussion is here: https://github.com/divio/django-cms/issues/1079 # This stuff is still documented as removed, and WILL be removed again in the next release. # All new code should use _mptt_meta rather than _meta for tree attributes. attrs = set(['left_attr', 'right_attr', 'tree_id_attr', 'level_attr', 'parent_attr', 'tree_manager_attr', 'order_insertion_by']) warned_attrs = set() class _MetaSubClass(cls._meta.__class__): def __getattr__(self, attr): if attr in attrs: if attr not in warned_attrs: warned_attrs.add(attr) return getattr(cls._mptt_meta, attr) return super(_MetaSubClass, self).__getattr__(attr) cls._meta.__class__ = _MetaSubClass try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, 'objects', None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') if hasattr(manager, 'init_from_model'): manager.init_from_model(cls) # make sure we have a tree manager somewhere tree_manager = TreeManager() tree_manager.contribute_to_class(cls, '_tree_manager') tree_manager.init_from_model(cls) # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, '_tree_manager', tree_manager) # for backwards compatibility, add .tree too (or whatever's in tree_manager_attr) tree_manager_attr = cls._mptt_meta.tree_manager_attr if tree_manager_attr != 'objects': another = getattr(cls, tree_manager_attr, None) if another is None: # wrap with a warning on first use from django.db.models.manager import ManagerDescriptor class _WarningDescriptor(ManagerDescriptor): def __init__(self, manager): self.manager = manager self.used = False def __get__(self, instance, type=None): if instance != None: raise AttributeError("Manager isn't accessible via %s instances" % type.__name__) if not self.used: self.used = True return self.manager setattr(cls, tree_manager_attr, _WarningDescriptor(manager)) elif hasattr(another, 'init_from_model'): another.init_from_model(cls) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError( _("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) if _get_tree_model(cls) is cls: # HACK: _meta.get_field() doesn't work before AppCache.ready in Django>=1.8 # ( see https://code.djangoproject.com/ticket/24231 ) # So the only way to get existing fields is using local_fields on all superclasses. existing_field_names = set() for base in cls.mro(): if hasattr(base, '_meta'): existing_field_names.update( [f.name for f in base._meta.local_fields]) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) if field_name not in existing_field_names: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, 'objects', None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') # make sure we have a tree manager somewhere tree_manager = None attrs = dir(cls) if "objects" in attrs and isinstance(cls.objects, TreeManager): tree_manager = cls.objects # Go look for it somewhere else else: for attr in sorted(attrs): try: # HACK: avoid using getattr(cls, attr) # because it calls __get__ on descriptors, which can cause nasty side effects # with more inconsiderate apps. # (e.g. django-tagging's TagField is a descriptor which can do db queries on getattr) # ( ref: http://stackoverflow.com/questions/27790344 ) obj = cls.__dict__[attr] except KeyError: continue if isinstance(obj, TreeManager): tree_manager = obj # prefer any locally defined manager (i.e. keep going if not local) if obj.model is cls: break if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, '_tree_manager') # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, '_tree_manager', tree_manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError( _("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) if _get_tree_model(cls) is cls: # HACK: _meta.get_field() doesn't work before AppCache.ready in Django>=1.8 # ( see https://code.djangoproject.com/ticket/24231 ) # So the only way to get existing fields is using local_fields on all superclasses. existing_field_names = set() for base in cls.mro(): if hasattr(base, '_meta'): existing_field_names.update( [f.name for f in base._meta.local_fields]) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) if field_name not in existing_field_names: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already # NOTE: Django 1.10 lets models inherit managers without handholding. if django.VERSION < (1, 10) and not cls._meta.abstract: manager = getattr(cls, 'objects', None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') # make sure we have a tree manager somewhere tree_manager = None if hasattr(cls._meta, 'concrete_managers'): # Django < 1.10 cls_managers = cls._meta.concrete_managers + cls._meta.abstract_managers cls_managers = [r[2] for r in cls_managers] else: cls_managers = cls._meta.managers for cls_manager in cls_managers: if isinstance(cls_manager, TreeManager): # prefer any locally defined manager (i.e. keep going if not local) if cls_manager.model is cls: tree_manager = cls_manager break if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, '_default_manager') return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError(_("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, 'objects', None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') if hasattr(manager, 'init_from_model'): manager.init_from_model(cls) # make sure we have a tree manager somewhere tree_manager = None for attr in sorted(dir(cls)): try: obj = getattr(cls, attr) except AttributeError: continue if isinstance(obj, TreeManager): tree_manager = obj # prefer any locally defined manager (i.e. keep going if not local) if obj.model is cls: break if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, '_tree_manager') tree_manager.init_from_model(cls) # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, '_tree_manager', tree_manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError, "register() expects a Django model class argument" if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) # For backwards compatibility with existing libraries, we copy the # _mptt_meta options into _meta. # This will be removed in 0.5. # All new code should use _mptt_meta rather than _meta for tree attributes. for attr in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr', 'parent_attr', 'tree_manager_attr', 'order_insertion_by'): setattr(cls._meta, attr, getattr(cls._mptt_meta, attr)) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: tree_manager_attr = cls._mptt_meta.tree_manager_attr manager = getattr(cls, tree_manager_attr, None) if (not manager) or manager.model != cls: if not manager: manager = TreeManager() else: # manager.model might already be set if this is a proxy model # (in that case, we need to create a new manager, or _base_manager will be wrong) manager = manager.__class__() manager.contribute_to_class(cls, tree_manager_attr) manager.init_from_model(cls) setattr(cls, '_tree_manager', manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError( _("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) # For backwards compatibility with existing libraries, we copy the # _mptt_meta options into _meta. # This was removed in 0.5 but added back in 0.5.1 since it caused compatibility # issues with django-cms 2.2.0. # some discussion is here: https://github.com/divio/django-cms/issues/1079 # This stuff is still documented as removed, and WILL be removed again in the next release. # All new code should use _mptt_meta rather than _meta for tree attributes. attrs = set([ 'left_attr', 'right_attr', 'tree_id_attr', 'level_attr', 'parent_attr', 'tree_manager_attr', 'order_insertion_by' ]) warned_attrs = set() class _MetaSubClass(cls._meta.__class__): def __getattr__(self, attr): if attr in attrs: if attr not in warned_attrs: warnings.warn( "%s._meta.%s is deprecated and will be removed in mptt 0.6" % (cls.__name__, attr), #don't use DeprecationWarning, that gets ignored by default UserWarning, ) warned_attrs.add(attr) return getattr(cls._mptt_meta, attr) return super(_MetaSubClass, self).__getattr__(attr) cls._meta.__class__ = _MetaSubClass try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, 'objects', None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') if hasattr(manager, 'init_from_model'): manager.init_from_model(cls) # make sure we have a tree manager somewhere tree_manager = TreeManager() tree_manager.contribute_to_class(cls, '_tree_manager') tree_manager.init_from_model(cls) # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, '_tree_manager', tree_manager) # for backwards compatibility, add .tree too (or whatever's in tree_manager_attr) tree_manager_attr = cls._mptt_meta.tree_manager_attr if tree_manager_attr != 'objects': another = getattr(cls, tree_manager_attr, None) if another is None: # wrap with a warning on first use from django.db.models.manager import ManagerDescriptor class _WarningDescriptor(ManagerDescriptor): def __init__(self, manager): self.manager = manager self.used = False def __get__(self, instance, type=None): if instance != None: raise AttributeError( "Manager isn't accessible via %s instances" % type.__name__) if not self.used: warnings.warn( 'Implicit manager %s.%s will be removed in django-mptt 0.6. ' ' Explicitly define a TreeManager() on your model to remove this warning.' % (cls.__name__, tree_manager_attr), DeprecationWarning) self.used = True return self.manager setattr(cls, tree_manager_attr, _WarningDescriptor(manager)) elif hasattr(another, 'init_from_model'): another.init_from_model(cls) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError(_("register() expects a Django model class argument")) if not hasattr(cls, "_mptt_meta"): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, "abstract", False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) is_cls_tree_model = _get_tree_model(cls) is cls if is_cls_tree_model: # HACK: _meta.get_field() doesn't work before AppCache.ready in Django>=1.8 # ( see https://code.djangoproject.com/ticket/24231 ) # So the only way to get existing fields is using local_fields on all superclasses. existing_field_names = set() for base in cls.mro(): if hasattr(base, "_meta"): existing_field_names.update( [f.name for f in base._meta.local_fields] ) mptt_meta = cls._mptt_meta indexed_attrs = (mptt_meta.tree_id_attr,) field_names = ( mptt_meta.left_attr, mptt_meta.right_attr, mptt_meta.tree_id_attr, mptt_meta.level_attr, ) for field_name in field_names: if field_name not in existing_field_names: field = models.PositiveIntegerField( db_index=field_name in indexed_attrs, editable=False ) field.contribute_to_class(cls, field_name) # Add an index_together on tree_id_attr and left_attr, as these are very # commonly queried (pretty much all reads). index_together = (cls._mptt_meta.tree_id_attr, cls._mptt_meta.left_attr) if index_together not in cls._meta.index_together: cls._meta.index_together += (index_together,) # Add a tree manager, if there isn't one already if not abstract: # make sure we have a tree manager somewhere tree_manager = None # Use the default manager defined on the class if any if cls._default_manager and isinstance( cls._default_manager, TreeManager ): tree_manager = cls._default_manager else: for cls_manager in cls._meta.managers: if isinstance(cls_manager, TreeManager): # prefer any locally defined manager (i.e. keep going if not local) if cls_manager.model is cls: tree_manager = cls_manager break if is_cls_tree_model: idx_together = ( cls._mptt_meta.tree_id_attr, cls._mptt_meta.left_attr, ) if idx_together not in cls._meta.index_together: cls._meta.index_together += (idx_together,) if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, "_tree_manager") # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, "_tree_manager", tree_manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError( _("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, 'objects', None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') if hasattr(manager, 'init_from_model'): manager.init_from_model(cls) # make sure we have a tree manager somewhere tree_manager = None for attr in sorted(dir(cls)): try: obj = getattr(cls, attr) except AttributeError: continue if isinstance(obj, TreeManager): tree_manager = obj # prefer any locally defined manager (i.e. keep going if not local) if obj.model is cls: break if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, '_tree_manager') tree_manager.init_from_model(cls) # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, '_tree_manager', tree_manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError(_("register() expects a Django model class argument")) if not hasattr(cls, "_mptt_meta"): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, "abstract", False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) if _get_tree_model(cls) is cls: # HACK: _meta.get_field() doesn't work before AppCache.ready in Django>=1.8 # ( see https://code.djangoproject.com/ticket/24231 ) # So the only way to get existing fields is using local_fields on all superclasses. existing_field_names = set() for base in cls.mro(): if hasattr(base, "_meta"): existing_field_names.update([f.name for f in base._meta.local_fields]) for key in ("left_attr", "right_attr", "tree_id_attr", "level_attr"): field_name = getattr(cls._mptt_meta, key) if field_name not in existing_field_names: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, "objects", None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, "objects") elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, "objects") # make sure we have a tree manager somewhere tree_manager = None attrs = dir(cls) if "objects" in attrs and isinstance(cls.objects, TreeManager): tree_manager = cls.objects # Go look for it somewhere else else: for attr in sorted(attrs): try: # HACK: avoid using getattr(cls, attr) # because it calls __get__ on descriptors, which can cause nasty side effects # with more inconsiderate apps. # (e.g. django-tagging's TagField is a descriptor which can do db queries on getattr) # ( ref: http://stackoverflow.com/questions/27790344 ) obj = cls.__dict__[attr] except KeyError: continue if isinstance(obj, TreeManager): tree_manager = obj # prefer any locally defined manager (i.e. keep going if not local) if obj.model is cls: break if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, "_tree_manager") # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, "_tree_manager", tree_manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError(_("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) if _get_tree_model(cls) is cls: # HACK: _meta.get_field() doesn't work before AppCache.ready in Django>=1.8 # ( see https://code.djangoproject.com/ticket/24231 ) # So the only way to get existing fields is using local_fields on all superclasses. existing_field_names = set() for base in cls.mro(): if hasattr(base, '_meta'): existing_field_names.update([f.name for f in base._meta.local_fields]) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) if field_name not in existing_field_names: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: # make sure we have a tree manager somewhere tree_manager = None if hasattr(cls._meta, 'concrete_managers'): # Django < 1.10 cls_managers = cls._meta.concrete_managers + cls._meta.abstract_managers cls_managers = [r[2] for r in cls_managers] else: cls_managers = cls._meta.managers for cls_manager in cls_managers: if isinstance(cls_manager, TreeManager): # prefer any locally defined manager (i.e. keep going if not local) if cls_manager.model is cls: tree_manager = cls_manager break if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, '_tree_manager') # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, '_tree_manager', tree_manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError(_("register() expects a Django model class argument")) if not hasattr(cls, "_mptt_meta"): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, "abstract", False) # For backwards compatibility with existing libraries, we copy the # _mptt_meta options into _meta. # This was removed in 0.5 but added back in 0.5.1 since it caused compatibility # issues with django-cms 2.2.0. # some discussion is here: https://github.com/divio/django-cms/issues/1079 # This stuff is still documented as removed, and WILL be removed again in the next release. # All new code should use _mptt_meta rather than _meta for tree attributes. attrs = ( "left_attr", "right_attr", "tree_id_attr", "level_attr", "parent_attr", "tree_manager_attr", "order_insertion_by", ) warned_attrs = set() class _MetaSubClass(cls._meta.__class__): def __getattr__(self, attr): if attr in attrs: if attr not in warned_attrs: warnings.warn( "%s._meta.%s is deprecated and will be removed in mptt 0.6" % (cls.__name__, attr), # don't use DeprecationWarning, that gets ignored by default UserWarning, ) warned_attrs.add(attr) return getattr(cls._mptt_meta, attr) return super(_MetaSubClass, self).__getattr__(attr) cls._meta.__class__ = _MetaSubClass try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in xrange(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ("left_attr", "right_attr", "tree_id_attr", "level_attr"): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, "objects", None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, "objects") elif manager.model != cls: # manager was inherited manager = manager._copy_to_model(cls) manager.contribute_to_class(cls, "objects") if hasattr(manager, "init_from_model"): manager.init_from_model(cls) # make sure we have a tree manager somewhere tree_manager = None for attr in sorted(dir(cls)): try: obj = getattr(cls, attr) except AttributeError: continue if isinstance(obj, TreeManager): tree_manager = obj # prefer any locally defined manager (i.e. keep going if not local) if obj.model is cls: break if tree_manager and tree_manager.model is not cls: tree_manager = tree_manager._copy_to_model(cls) elif tree_manager is None: tree_manager = TreeManager() tree_manager.contribute_to_class(cls, "_tree_manager") tree_manager.init_from_model(cls) # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, "_tree_manager", tree_manager) return cls
def register(meta, cls, **kwargs): """ For the weird cases when you need to add tree-ness to an *existing* class. For other cases you should subclass MPTTModel instead of calling this. """ if not issubclass(cls, models.Model): raise ValueError(_("register() expects a Django model class argument")) if not hasattr(cls, '_mptt_meta'): cls._mptt_meta = MPTTOptions(**kwargs) abstract = getattr(cls._meta, 'abstract', False) try: MPTTModel except NameError: # We're defining the base class right now, so don't do anything # We only want to add this stuff to the subclasses. # (Otherwise if field names are customized, we'll end up adding two # copies) pass else: if not issubclass(cls, MPTTModel): bases = list(cls.__bases__) # strip out bases that are strict superclasses of MPTTModel. # (i.e. Model, object) # this helps linearize the type hierarchy if possible for i in range(len(bases) - 1, -1, -1): if issubclass(MPTTModel, bases[i]): del bases[i] bases.insert(0, MPTTModel) cls.__bases__ = tuple(bases) for key in ('left_attr', 'right_attr', 'tree_id_attr', 'level_attr'): field_name = getattr(cls._mptt_meta, key) try: cls._meta.get_field(field_name) except models.FieldDoesNotExist: field = models.PositiveIntegerField(db_index=True, editable=False) field.contribute_to_class(cls, field_name) # Add a tree manager, if there isn't one already if not abstract: manager = getattr(cls, 'objects', None) if manager is None: manager = cls._default_manager._copy_to_model(cls) manager.contribute_to_class(cls, 'objects') if hasattr(manager, 'init_from_model'): manager.init_from_model(cls) # make sure we have a tree manager somewhere if not isinstance(manager, TreeManager): manager = TreeManager() manager.contribute_to_class(cls, '_tree_manager') manager.init_from_model(cls) # avoid using ManagerDescriptor, so instances can refer to self._tree_manager setattr(cls, '_tree_manager', manager) # for backwards compatibility, add .tree too (or whatever's in tree_manager_attr) tree_manager_attr = cls._mptt_meta.tree_manager_attr if tree_manager_attr != 'objects': another = getattr(cls, tree_manager_attr, None) if another is None: # wrap with a warning on first use from django.db.models.manager import ManagerDescriptor class _WarningDescriptor(ManagerDescriptor): def __init__(self, manager): self.manager = manager self.used = False def __get__(self, instance, type=None): if instance != None: raise AttributeError("Manager isn't accessible via %s instances" % type.__name__) if not self.used: warnings.warn( 'Implicit manager %s.%s will be removed in django-mptt 0.6. ' ' Explicitly define a TreeManager() on your model to remove this warning.' % (cls.__name__, tree_manager_attr), DeprecationWarning ) self.used = True return self.manager setattr(cls, tree_manager_attr, _WarningDescriptor(manager)) elif hasattr(another, 'init_from_model'): another.init_from_model(cls) return cls