Nearly complete support for Tags
authorElrond <elrond+mediagoblin.org@samba-tng.org>
Wed, 4 Jan 2012 21:00:44 +0000 (22:00 +0100)
committerElrond <elrond+mediagoblin.org@samba-tng.org>
Sat, 28 Jan 2012 18:32:43 +0000 (19:32 +0100)
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.

mediagoblin/db/sql/base.py
mediagoblin/db/sql/models.py
mediagoblin/edit/views.py
mediagoblin/submit/views.py

index 1db53c56728e549c46970188190b411110612900..f1affc83e15177375c6f4b81473c8b735fcf5bcf 100644 (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))
index 6232fff856b3df0606f7edf863fd73ffa47843c8..9abd8ec7f14cc9da68b11630c953da9dcdf8ed09 100644 (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)
-    tag = Column(Integer, ForeignKey('tags.id'), nullable=False)
-    name = Column(Unicode)
     media_entry = Column(
-        Integer, ForeignKey('media_entries.id'),
+        Integer, ForeignKey(MediaEntry.id),
         nullable=False)
+    tag = Column(Integer, ForeignKey('tags.id'), nullable=False)
+    name = Column(Unicode)
     # 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"
index cf7182e564109c98138c083b5ca968bbc8f666ae..a637d6998993e0b404f1e7f1ac03594167f2878d 100644 (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(
index f70e4ba5ffff7ef8eb9321ef82beba69ad841c5f..0efee803afde3323857496f6d7ae98b135dd9da6 100644 (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