抱歉,我想不出更好的通用标题。我正在使用金字塔和sqlalchemy构建照片投票应用程序。完整的架构和orm在最后,但最相关的信息是
photo
表vote
表格photo_id
和user_id
,其中后者表示在照片上下投票的用户。 category
表格中包含照片类别列表photocategory
表格链接photo
和category
表格在应用的主要照片Feed中,我想按以下顺序显示照片
该应用还可以灵活地显示某些类别的照片
我现在正在实施的方式是......
即
photos = DBSession.query(Photos).join(photocategory, Photo.id==photocategory.c.photo_id).filter(photocategory.c.category_id==__CATEGORY_ID_HERE__).all()
photos
即
photos = sorted(photos, key=lambda photo: len(photo.votes), reverse=True)
photos
以查看用户是否已投票,并将照片附加到voted
或unvoted
列表/数组然而,这是非常低效的,因为我必须搜索用户之前为photos
中的每张照片投票的所有照片,所以我想知道什么是正确有效的方法来做到这一点。谢谢
SCHEMA
photo_table = schema.Table('photo', metadata,
schema.Column('id', types.Integer,
schema.Sequence('photo_seq_id'), primary_key=True),
schema.Column('caption', types.UnicodeText(), nullable=True),
schema.Column('timestamp', types.TIMESTAMP(), default=datetime.now()),
schema.Column('last_updated', types.TIMESTAMP(), default=datetime.now(),),
schema.Column('spam', types.Boolean, default=0),
schema.Column('trash', types.Boolean, default=0),
schema.Column('image_path', types.Unicode(255), nullable=False),
schema.Column('user_id', types.Integer, schema.ForeignKey('user.id', ondelete='CASCADE')),
mysql_engine='InnoDB'
)
category_table = schema.Table('category', metadata,
schema.Column('id', types.Integer,
schema.Sequence('category_seq_id'), primary_key=True),
schema.Column('name', types.Unicode(255), nullable=False, unique=True),
mysql_engine='InnoDB'
)
photocategory_table = schema.Table('photocategory', metadata,
schema.Column('photo_id', types.Integer, schema.ForeignKey('photo.id', ondelete='CASCADE'), primary_key=True),
schema.Column('category_id', types.Integer, schema.ForeignKey('category.id', ondelete='CASCADE'), primary_key=True),
mysql_engine='InnoDB'
)
vote_table = schema.Table('vote', metadata,
schema.Column('id', types.Integer,
schema.Sequence('vote_seq_id'), primary_key=True),
schema.Column('timestamp', types.TIMESTAMP(), default=datetime.now()),
schema.Column('upvote', types.Boolean, nullable=False),
schema.Column('photo_id', types.Integer, schema.ForeignKey('photo.id', ondelete='CASCADE')),
schema.Column('user_id', types.Integer, schema.ForeignKey('user.id', ondelete='CASCADE')),
mysql_engine='InnoDB'
)
ORM Mapper
orm.mapper(Photo, photo_table, properties={
'votes': orm.relation(Vote, backref='photo', lazy='dynamic'),
'categories': orm.relation(Category, secondary=photocategory_table, backref='photos'),
})
orm.mapper(User, user_table, properties={
'photos': orm.relation(Photo, backref='owner'),
'votes': orm.relation(Vote, backref='voter', lazy='dynamic'),
})
答案 0 :(得分:0)
也许使用SQL本身做这个是一个更好的主意。以下是未经测试的,可能无法正常工作,但您可以调整它以满足您的需求
您可以按
选择类别的照片cat_photos = session.query(PhotoCategory.photo_id.label('pid')).options(lazyload('*')).filter(PhotoCategory.category_id==SOMEID).subquery()
加入用户和照片表以获取用户可以投票的照片列表。假设用户无法对自己的照片进行投票,那么
elig_photos = session.query(User).join(Photos,Photos.user_id!=User.id).options(lazyload('*')).with_entities(Photos.id.label('pid'),User.id.label('uid').subquery()
现在您可以将其加入到投票表和子查询中,以获取用户尚未投票的特定类别的照片
not_voted = session.query(elig_photos).outerjoin(Votes,and_(Votes.photo_id==elig_photos.c.pid,Votes.user_id==elig_photos.c.uid)).join(cat_photos,cat_photos.c.pid==elig_photos.c.pid).with_entities(elig_photos.c.pid.label('photo_id'),Votes.upvote.label('upvote')).options(lazyload('*')).filter(User.id==SOMEUSER).filter(Votes.upvote==None).all()
按照投票数量获取此类别的照片。我们将不得不进行左连接,因为可能有一些照片尚无人投票
sorted_votes = session.query(cat_photos).outerjoin(Votes,cat_photos.c.pid==Votes.photo_id).with_entities(cat_photos.c.pid.label('pid'),func.coalesce(func.sum(Votes.upvote),0).label('sum_votes')).options(lazyload('*')).group_by(cat_photos.pid).order_by(desc('sum_votes')).all()
注意 - 我已为每个查询添加了一个选项options(lazyload('*'))
,以使关系延迟加载
现在你有两个清单 -
sorted_votes
以降序列出此类别的照片
投票顺序(0票对未经任何人投票的照片)not_voted
列出了此类别的照片未经用户投票请注意,用户上传的此类别照片将是第一个列表的一部分
您可以在python中处理这两个列表,根据第一个列表中的索引显示not_voted,然后显示第一个列表的其余部分
not_voted_sorted = sorted(not_voted,key=lambda x:sorted_votes.index(x))
rest_of_the_photos = [y for y in sorted_votes if y not in not_voted]
如果您只从这些查询中获取photo_id,那将是一个好主意(IMO)。整个Photo对象列表可以与DB分开获取,并保存在以photo_id为关键字的字典中。因此,如果您知道要显示的photo_id,则可以在模板中显示整个照片详细信息。
最后注意:如果某些内容不起作用,请尝试为您要执行的操作编写一个纯SQL,然后编写SQLAlchemy等效项并打印该语句以进行比较,如果您手写的SQL和SQLAlchemy生成的SQL是是否相同