Rewrite media_data handling to use relationships

Instead of doing query by hand, use the relationships on
the models to find the media_data. Is is made possible by
the BACKREF_NAME in each models.py, which lets us know the
local attr to ask for.

Also initialize the relationship attribute on new
media_data instead of the media_id. Also do not add it to
the session. This gives us:
- This automatically initializes the other side of the
  relationship, which will allow later acces via that way.
- If the media_data is too early in the session, when the
  (new) media_entry is not yet in there, this could get
  conflicts. Avoid those by not adding to session.
- Uses cascading to commit media_data together with the
  media_entry.
This commit is contained in:
Elrond 2013-02-01 15:42:44 +01:00
parent d728c636b9
commit 57f8d263e1

View File

@ -20,7 +20,7 @@ TODO: indexes on foreignkeys, where useful.
import logging import logging
import datetime import datetime
import sys from collections import Sequence
from sqlalchemy import Column, Integer, Unicode, UnicodeText, DateTime, \ from sqlalchemy import Column, Integer, Unicode, UnicodeText, DateTime, \
Boolean, ForeignKey, UniqueConstraint, PrimaryKeyConstraint, \ Boolean, ForeignKey, UniqueConstraint, PrimaryKeyConstraint, \
@ -32,9 +32,10 @@ from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.util import memoized_property from sqlalchemy.util import memoized_property
from mediagoblin.db.extratypes import PathTupleWithSlashes, JSONEncoded from mediagoblin.db.extratypes import PathTupleWithSlashes, JSONEncoded
from mediagoblin.db.base import Base, DictReadAttrProxy, Session from mediagoblin.db.base import Base, DictReadAttrProxy
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin, CollectionMixin, CollectionItemMixin from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, MediaCommentMixin, CollectionMixin, CollectionItemMixin
from mediagoblin.tools.files import delete_media_files from mediagoblin.tools.files import delete_media_files
from mediagoblin.tools.common import import_component
# It's actually kind of annoying how sqlalchemy-migrate does this, if # It's actually kind of annoying how sqlalchemy-migrate does this, if
# I understand it right, but whatever. Anyway, don't remove this :P # I understand it right, but whatever. Anyway, don't remove this :P
@ -165,7 +166,6 @@ class MediaEntry(Base, MediaEntryMixin):
collections = association_proxy("collections_helper", "in_collection") collections = association_proxy("collections_helper", "in_collection")
## TODO ## TODO
# media_data
# fail_error # fail_error
def get_comments(self, ascending=False): def get_comments(self, ascending=False):
@ -195,40 +195,41 @@ class MediaEntry(Base, MediaEntryMixin):
if media is not None: if media is not None:
return media.url_for_self(urlgen) return media.url_for_self(urlgen)
#@memoized_property
@property @property
def media_data(self): def media_data(self):
session = Session() r = getattr(self, self.media_data_ref, None)
if isinstance(r, Sequence):
return session.query(self.media_data_table).filter_by( assert len(r) < 2
media_entry=self.id).first() if r:
return r[0]
else:
return None
return r
def media_data_init(self, **kwargs): def media_data_init(self, **kwargs):
""" """
Initialize or update the contents of a media entry's media_data row Initialize or update the contents of a media entry's media_data row
""" """
session = Session() media_data = self.media_data
media_data = session.query(self.media_data_table).filter_by(
media_entry=self.id).first()
# No media data, so actually add a new one
if media_data is None: if media_data is None:
# No media data, so actually add a new one
media_data = self.media_data_table( media_data = self.media_data_table(
media_entry=self.id,
**kwargs) **kwargs)
session.add(media_data) # Get the relationship set up.
# Update old media data media_data.get_media_entry = self
else: else:
# Update old media data
for field, value in kwargs.iteritems(): for field, value in kwargs.iteritems():
setattr(media_data, field, value) setattr(media_data, field, value)
@memoized_property @memoized_property
def media_data_table(self): def media_data_table(self):
# TODO: memoize this return import_component(self.media_type + '.models:DATA_MODEL')
models_module = self.media_type + '.models'
__import__(models_module) @memoized_property
return sys.modules[models_module].DATA_MODEL def media_data_ref(self):
return import_component(self.media_type + '.models:BACKREF_NAME')
def __repr__(self): def __repr__(self):
safe_title = self.title.encode('ascii', 'replace') safe_title = self.title.encode('ascii', 'replace')