class Node(Base, ContainerMixin, PersistentACLMixin, metaclass=NodeMeta): """Basic node in the persistance hierarchy. """ __table_args__ = (UniqueConstraint("parent_id", "name"), ) __mapper_args__ = dict(polymorphic_on="type", polymorphic_identity="node", with_polymorphic="*") #: Primary key for the node in the DB #: (:class:`sqlalchemy.types.Integer`) id = Column(Integer(), primary_key=True) #: Lowercase class name of the node instance #: (:class:`sqlalchemy.types.String`) type = Column(String(30), nullable=False) #: ID of the node's parent #: (:class:`sqlalchemy.types.Integer`) parent_id = Column(ForeignKey("nodes.id"), index=True) #: Position of the node within its container / parent #: (:class:`sqlalchemy.types.Integer`) position = Column(Integer()) _acl = Column(MutationList.as_mutable(ACLType)) #: Name of the node as used in the URL #: (:class:`sqlalchemy.types.Unicode`) name = Column(Unicode(250), nullable=False) #: Title of the node, e.g. as shown in search results #: (:class:`sqlalchemy.types.Unicode`) title = Column(Unicode(250)) #: Annotations can be used to store arbitrary data in a nested dictionary #: (:class:`kotti.sqla.NestedMustationDict`) annotations = Column(NestedMutationDict.as_mutable(JsonType)) #: The path can be used to efficiently filter for child objects #: (:class:`sqlalchemy.types.Unicode`). path = Column(Unicode(2000), index=True) parent = relation( "Node", remote_side=[id], backref=backref( "_children", collection_class=ordering_list("position", reorder_on_append=True), order_by=[position], cascade="all", ), ) local_groups = relation(LocalGroup, backref=backref("node"), cascade="all", lazy="joined") __hash__ = Base.__hash__ def __init__(self, name: str = None, parent: "Node" = None, title: str = "", annotations: dict = None, **kwargs): """Constructor""" super().__init__(**kwargs) if annotations is None: annotations = {} self.parent = parent self.name = name self.title = title self.annotations = annotations @property def __name__(self): return self.name @property def __parent__(self): return self.parent @__parent__.setter def __parent__(self, value): self.parent = value def __repr__(self) -> str: return "<{} {} at {}>".format(self.__class__.__name__, self.id, resource_path(self)) def __eq__(self, other: Any) -> bool: return isinstance(other, Node) and self.id == other.id def __ne__(self, other: Any) -> bool: return not self == other copy_properties_blacklist = ( "id", "parent", "parent_id", "_children", "local_groups", "_tags", ) def clear(self) -> None: DBSession.query(Node).filter(Node.parent == self).delete() def copy(self, **kwargs) -> "Node": """ :result: A copy of the current instance :rtype: :class:`~kotti.resources.Node` """ children = list(self.children) copy = self.__class__() for prop in object_mapper(self).iterate_properties: if prop.key not in self.copy_properties_blacklist: setattr(copy, prop.key, getattr(self, prop.key)) for key, value in kwargs.items(): setattr(copy, key, value) for child in children: copy.children.append(child.copy()) return copy
class Node(Base, ContainerMixin, PersistentACLMixin): """Basic node in the persistance hierarchy. """ __table_args__ = (UniqueConstraint('parent_id', 'name'), ) __mapper_args__ = dict( polymorphic_on='type', polymorphic_identity='node', with_polymorphic='*', ) #: Primary key for the node in the DB #: (:class:`sqlalchemy.types.Integer`) id = Column(Integer(), primary_key=True) #: Lowercase class name of the node instance #: (:class:`sqlalchemy.types.String`) type = Column(String(30), nullable=False) #: ID of the node's parent #: (:class:`sqlalchemy.types.Integer`) parent_id = Column(ForeignKey('nodes.id'), index=True) #: Position of the node within its container / parent #: (:class:`sqlalchemy.types.Integer`) position = Column(Integer()) _acl = Column(MutationList.as_mutable(ACLType)) #: Name of the node as used in the URL #: (:class:`sqlalchemy.types.Unicode`) name = Column(Unicode(250), nullable=False) #: Title of the node, e.g. as shown in search results #: (:class:`sqlalchemy.types.Unicode`) title = Column(Unicode(250)) #: Annotations can be used to store arbitrary data in a nested dictionary #: (:class:`kotti.sqla.NestedMustationDict`) annotations = Column(NestedMutationDict.as_mutable(JsonType)) #: The path can be used to efficiently filter for child objects #: (:class:`sqlalchemy.types.Unicode`). path = Column(Unicode(2000), index=True) parent = relation('Node', remote_side=[id], backref=backref( '_children', collection_class=ordering_list( 'position', reorder_on_append=True), order_by=[position], cascade='all', )) local_groups = relation( LocalGroup, backref=backref('node'), cascade='all', lazy='joined', ) def __init__(self, name=None, parent=None, title=u"", annotations=None, **kwargs): """Constructor""" super(Node, self).__init__(**kwargs) if annotations is None: annotations = {} self.parent = parent self.name = name self.title = title self.annotations = annotations @property def __name__(self): return self.name @property def __parent__(self): return self.parent @__parent__.setter def __parent__(self, value): self.parent = value def __repr__(self): return u'<{0} {1} at {2}>'.format(self.__class__.__name__, self.id, resource_path(self)) def __eq__(self, other): return isinstance(other, Node) and self.id == other.id def __ne__(self, other): return not self == other copy_properties_blacklist = ('id', 'parent', 'parent_id', '_children', 'local_groups', '_tags') def copy(self, **kwargs): """ :result: A copy of the current instance :rtype: :class:`~kotti.resources.Node` """ children = list(self.children) copy = self.__class__() for prop in object_mapper(self).iterate_properties: if prop.key not in self.copy_properties_blacklist: setattr(copy, prop.key, getattr(self, prop.key)) for key, value in kwargs.items(): setattr(copy, key, value) for child in children: copy.children.append(child.copy()) return copy
class Node(Base, ContainerMixin, PersistentACLMixin): implements(INode) __table_args__ = (UniqueConstraint('parent_id', 'name'), ) __mapper_args__ = dict( polymorphic_on='type', polymorphic_identity='node', with_polymorphic='*', ) id = Column(Integer(), primary_key=True) type = Column(String(30), nullable=False) parent_id = Column(ForeignKey('nodes.id')) position = Column(Integer()) _acl = Column(MutationList.as_mutable(ACLType)) name = Column(Unicode(50), nullable=False) title = Column(Unicode(100)) annotations = Column(NestedMutationDict.as_mutable(JsonType)) _children = relation( 'Node', collection_class=ordering_list('position'), order_by=[position], backref=backref('parent', remote_side=[id]), cascade='all', ) local_groups = relation( LocalGroup, backref=backref('node'), cascade='all', ) def __init__(self, name=None, parent=None, title=u"", annotations=None): if annotations is None: annotations = {} self.name = name self.parent = parent self.title = title self.annotations = annotations @property def __name__(self): return self.name @property def __parent__(self): return self.parent @__parent__.setter def __parent__(self, value): self.parent = value def __repr__(self): return '<%s %s at %s>' % (self.__class__.__name__, self.id, resource_path(self)) def __eq__(self, other): return isinstance(other, Node) and self.id == other.id def __ne__(self, other): return not self == other copy_properties_blacklist = ('id', 'parent', 'parent_id', '_children', 'local_groups', '_tags') def copy(self, **kwargs): children = list(self.children) copy = self.__class__() for prop in object_mapper(self).iterate_properties: if prop.key not in self.copy_properties_blacklist: setattr(copy, prop.key, getattr(self, prop.key)) for key, value in kwargs.items(): setattr(copy, key, value) for child in children: copy.children.append(child.copy()) return copy