Nearly complete support for Tags

These changes allow all of the rest of the code to use tags
in sql as they were used on mongo. It's not efficient at
all, as changing tags usually means to remove all old tags
and adding all new.

The only problem here is: Old slugs for tags are not
removed, because they're shared across all MediaTags and
dropping orphans is not always easy.
This commit is contained in:
Elrond 2012-01-04 22:00:44 +01:00
parent ebc0e38239
commit de91730336
4 changed files with 54 additions and 6 deletions

View File

@ -77,3 +77,19 @@ class GMGTableBase(object):
Base = declarative_base(cls=GMGTableBase)
class DictReadAttrProxy(object):
"""
Maps read accesses to obj['key'] to obj.key
and hides all the rest of the obj
"""
def __init__(self, proxied_obj):
self.proxied_obj = proxied_obj
def __getitem__(self, key):
try:
return getattr(self.proxied_obj, key)
except AttributeError:
raise KeyError("%r is not an attribute on %r"
% (key, self.proxied_obj))

View File

@ -26,7 +26,7 @@ from sqlalchemy.sql.expression import desc
from sqlalchemy.ext.associationproxy import association_proxy
from mediagoblin.db.sql.extratypes import PathTupleWithSlashes
from mediagoblin.db.sql.base import Base
from mediagoblin.db.sql.base import Base, DictReadAttrProxy
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin
@ -101,6 +101,13 @@ class MediaEntry(Base, MediaEntryMixin):
creator=lambda k, v: MediaFile(name=k, file_path=v)
)
tags_helper = relationship("MediaTag",
cascade="all, delete-orphan"
)
tags = association_proxy("tags_helper", "dict_view",
creator=lambda v: MediaTag(name=v["name"], slug=v["slug"])
)
## TODO
# media_data
# attachment_files
@ -153,22 +160,47 @@ class Tag(Base):
id = Column(Integer, primary_key=True)
slug = Column(Unicode, nullable=False, unique=True)
def __repr__(self):
return "<Tag %r: %r>" % (self.id, self.slug)
@classmethod
def find_or_new(cls, slug):
t = cls.query.filter_by(slug=slug).first()
if t is not None:
return t
return cls(slug=slug)
class MediaTag(Base):
__tablename__ = "media_tags"
id = Column(Integer, primary_key=True)
media_entry = Column(
Integer, ForeignKey(MediaEntry.id),
nullable=False)
tag = Column(Integer, ForeignKey('tags.id'), nullable=False)
name = Column(Unicode)
media_entry = Column(
Integer, ForeignKey('media_entries.id'),
nullable=False)
# created = Column(DateTime, nullable=False, default=datetime.datetime.now)
__table_args__ = (
UniqueConstraint('tag', 'media_entry'),
{})
tag_helper = relationship(Tag)
slug = association_proxy('tag_helper', 'slug',
creator=Tag.find_or_new
)
def __init__(self, name, slug):
Base.__init__(self)
self.name = name
self.tag_helper = Tag.find_or_new(slug)
@property
def dict_view(self):
"""A dict like view on this object"""
return DictReadAttrProxy(self)
class MediaComment(Base):
__tablename__ = "media_comments"

View File

@ -69,7 +69,7 @@ def edit_media(request, media):
else:
media.title = unicode(request.POST['title'])
media.description = unicode(request.POST.get('description'))
media['tags'] = convert_to_tag_list_of_dicts(
media.tags = convert_to_tag_list_of_dicts(
request.POST.get('tags'))
media.description_html = cleaned_markdown_conversion(

View File

@ -74,7 +74,7 @@ def submit_start(request):
entry.uploader = request.user._id
# Process the user's folksonomy "tags"
entry['tags'] = convert_to_tag_list_of_dicts(
entry.tags = convert_to_tag_list_of_dicts(
request.POST.get('tags'))
# Generate a slug from the title