2014-01-07 53 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()