Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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()
Exemple #4
0
    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
Exemple #6
0
    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
Exemple #7
0
    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
Exemple #8
0
    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
Exemple #9
0
    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
Exemple #10
0
    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
Exemple #11
0
    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
Exemple #12
0
    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
Exemple #13
0
    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
Exemple #14
0
    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
Exemple #15
0
    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
Exemple #16
0
    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