Source code for abilian.core.models.tag

# coding=utf-8
"""
"""
from __future__ import absolute_import, print_function, division

import abc
from functools import total_ordering

import sqlalchemy as sa

from .base import Model, IdMixin
from abilian.core.entities import Entity


#: backref attribute on tagged elements
TAGS_ATTR = '__tags__'


[docs]class SupportTagging(object): """ """ __metaclass__ = abc.ABCMeta
[docs]def register(cls): """ Register an :class:`~.Entity` as a taggable class. Can be used as a class decorator: .. code-block:: python @tag.register class MyContent(Entity): .... """ if not issubclass(cls, Entity): raise ValueError('Class must be a subclass of abilian.core.entities.Entity') SupportTagging.register(cls) return cls
[docs]def is_support_tagging(obj): """ :param obj: a class or instance """ if isinstance(obj, type): return issubclass(obj, SupportTagging) if not isinstance(obj, SupportTagging): return False if obj.id is None: return False return True
entity_tag_tbl = sa.Table( 'entity_tags', Model.metadata, sa.Column('tag_id', sa.Integer, sa.ForeignKey('tag.id', ondelete='CASCADE')), sa.Column('entity_id', sa.Integer, sa.ForeignKey(Entity.id, ondelete='CASCADE')), sa.UniqueConstraint('tag_id', 'entity_id'), ) @total_ordering
[docs]class Tag(IdMixin, Model): """ Tags are text labels that can be attached to :class:`entities <.Entity>`. They are namespaced, so that independent group of tags can be defined in the application. The default namespace is `"default"`. """ __tablename__ = 'tag' #: namespace ns = sa.Column(sa.UnicodeText(), nullable=False, default=u'default', server_default=u'default') #: Label visible to the user label = sa.Column(sa.UnicodeText(), nullable=False) #: :class:`entities <.Entity>` attached to this tag entities = sa.orm.relationship( Entity, collection_class=set, secondary=entity_tag_tbl, backref=sa.orm.backref(TAGS_ATTR, collection_class=set), ) __mapper_args__ = { 'order_by': label, } __table_args__ = ( sa.UniqueConstraint('ns', 'label'), # namespace is not empty and is not surrounded by space characters sa.CheckConstraint( sa.sql.and_( sa.sql.func.trim(sa.sql.column('ns')) == sa.sql.column('ns'), sa.sql.column('ns') != u''), ), # label is not empty and is not surrounded by space characters sa.CheckConstraint( sa.sql.and_( sa.sql.func.trim(sa.sql.column('label')) == sa.sql.column('label'), sa.sql.column('label') != u''), ), ) def __unicode__(self): return self.label def __lt__(self, other): return unicode(self).lower().__lt__(unicode(other).lower()) def __repr__(self): cls = self.__class__ return '<{mod}.{cls} id={t.id!r} ns={t.ns!r} label={t.label!r} at 0x{addr:x}>'.format( mod=cls.__module__, cls=cls.__name__, t=self, addr=id(self), )