diff options
-rw-r--r-- | mediagoblin/db/sql/base.py | 16 | ||||
-rw-r--r-- | mediagoblin/db/sql/models.py | 40 | ||||
-rw-r--r-- | mediagoblin/edit/views.py | 2 | ||||
-rw-r--r-- | mediagoblin/submit/views.py | 2 |
4 files changed, 54 insertions, 6 deletions
diff --git a/mediagoblin/db/sql/base.py b/mediagoblin/db/sql/base.py index 1db53c56..f1affc83 100644 --- a/mediagoblin/db/sql/base.py +++ b/mediagoblin/db/sql/base.py @@ -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)) diff --git a/mediagoblin/db/sql/models.py b/mediagoblin/db/sql/models.py index 6232fff8..9abd8ec7 100644 --- a/mediagoblin/db/sql/models.py +++ b/mediagoblin/db/sql/models.py @@ -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" diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index cf7182e5..a637d699 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -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( diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index f70e4ba5..0efee803 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -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 |