2014-01-07 57 views
2

小背景:我正在创建一个Web应用程序(使用Flask)以便在组织内部使用。该webapp将有一个非常简单的留言板,允许用户张贴和评论帖子。高效查询SQLAlchemy中的关系

我这样做是出于几个原因 - 主要是为了获得Flask的经验并更好地理解sqlalchemy。

这是数据库架构与一些非重要的信息删除:

class User(db.Model): 
    id = db.Column(db.Integer, primary_key = True) 
    # information about user 
    posts = db.relationship('Post', backref = 'author', lazy = 'dynamic') 
    comments = db.relationship('Comment', backref = 'author', lazy = 'dynamic') 

class Post(db.Model): 
    id = db.Column(db.Integer, primary_key = True) 
    # information about posts (title, body, timestamp, etc.) 
    user_id = db.Column(db.Integer, db.ForeignKey('user.id')) 
    comments = db.relationship('Comment', backref = 'thread', lazy = 'dynamic') 

class Comment(db.Model): 
    id = db.Column(db.Integer, primary_key = True) 
    # information about comment (body, timestamp, etc) 
    user_id = db.Column(db.Integer, db.ForeignKey('user.id')) # author 
    post_id = db.Column(db.Integer, db.ForeignKey('post.id')) # thread 

当我渲染的消息来看,我希望能够显示线程表以下信息为每个消息:

  • 标题
  • 作者
  • #回复的
  • 时间最后修改

现在,我的查询来获得的消息是这样的:

messages = Post.query.filter_by(post_type = TYPE_MESSAGE).order_by('timestamp desc') 

随着该查询,我得到很容易地得到每篇文章的标题和作者。但是,它目前按消息创建日期(我知道这是错误的,并且我知道为什么)进行排序,并且我无法轻松获得答复的数量。

如果我通过邮件被循环,从而使它们在应用程序中,我访问message.comments属性,并用它来寻找长度和获得最新评论的时间戳,但我在假设纠正要获得该数据,它需要另一个数据库查询(要访问message.comments)?由于是这种情况,我可以通过一个查询(好的)得到所有消息的列表,但是如果我有消息,则需要n额外的数据库查询来填充消息视图,其中I想要,这远没有效率。

这使我想起我的主要问题:是否有可能使用聚合运营SQLAlchemy的,你会在一个普通的SQL查询来获取COUNT(comments)MAX(timestamp)messages原始查询?或者,还有没有探索过的另一个解决方案呢?理想情况下,我希望能够在一个查询中完成这一切。我查看了SQLAlchemy文档,找不到像这样的东西。谢谢!

+0

我相信大多数论坛软件通过在'Post'级别存储这两个值来解决这个问题。它消除了频繁显示信息的联接需求,特别是当您检索多个帖子时。 – dirn

+0

这很有道理。从你所说的话来看,似乎我不得不将一个属性添加到名为“Post”的回复中,并在每次添加评论时增加它。那么'Post'必须具有像add_comment(c)'函数的东西(不一定是好的设计 - 当注释被删除时会发生什么?),还是有另一种方法可以通过SQLAlchemy来添加注释引用特定“Post”的数据库? – jcomo

+0

就我个人而言,我会用数据库中的触发器来做到这一点。如果你想把东西放在ORM中,[Flask-SQLAlchemy支持一些信号](http://pythonhosted.org/Flask-SQLAlchemy/signals.html)。 – dirn

回答

0

用于计数,你可以试试这个(例子):

session.query(Comment).join(Post).filter_by(id=5).count() 

sess.query(Comment).join(Post).filter(Post.id==5).count() 

而且,是的,你可以用骨料:

sess.query(func.max(Comment.id)).join(Post).filter_by(id=5).all() 

sess.query(func.max(Comment.id)).join(Post).filter(Post.id==5).all()