創建博客-完善關注功能(2)

使用數據庫聯結查詢所關注用戶的文章

程序首頁目前按時間降序顯示數據庫中的所有文章,現在我們已經完成了關注功能,如果讓用戶選擇只查看所關注用戶發佈的博客文章就更好了

若想顯示所關注用戶發佈的所有文章,第一步顯然先要獲取這些用戶,然後獲取各用戶的文章,再按一定順序排列,寫入單獨列表,可是這種方式的伸縮性不好,隨着數據庫不斷變大,生成這個列表的工作量也不斷增長,而且分頁等操作也無法高效率完成,獲取博客文章的高效方式是隻用一次查詢

完成這個操作的數據庫操作稱爲聯結,聯結操作用到兩個或更多的數據表,在其中查找滿足指定條件的記錄組合,再把記錄組合插入一個臨時表中,這個臨時表就是聯結查詢的結果,理解聯結查詢的最好方式是實例講解

下表是一個users表實例,表中有3個用戶
這裏寫圖片描述

下表是對應的posts表,表中有幾篇博客文章
這裏寫圖片描述
最後,下面follows表顯示了誰關注誰,從這個表中你可以看出,john關注了david,susan關注了john,但david誰也沒關注
這裏寫圖片描述

若想獲得susan所關注用戶發佈的文章,就要合併posts表和follows表,首先過濾follows表,只留下關注者爲susan的記錄,即上表中的最後兩行,然後過濾posts表,留下author_id和過濾後的follows表中followed_id相等的記錄,把兩次過濾結果合併,組成臨時聯結表,這就能高效查詢susan所關注用戶的文章列表,下表是聯結操作的結果,表中用來執行鏈接操作的*標記:

id author_id* body followed_id followed_id*
2 1 john的博客文章 2 1
3 3 david的博客文章 2 3
4 1 john的第二篇博客文章 2 1

這個表中包含的博客文章都是用戶susan所關注用戶發佈的,使用Flask-SQLAlchemy執行這個聯結操作的查詢相當複雜:

return db.session.query(Post).select_from(Follow).\
    filter_by(follower_id=self.id).\
    join(Post, Follow.followed_id == Post.author_id)

在此之前見到的查詢都是從所查詢模型的query屬性開始的,這種查詢不能在這裏使用,因爲查詢要返回posts記錄,所以首先要做的操作是在follow表上執行過濾器,因此,這裏使用了一種更基礎的查詢方式,爲了完全理解上述查詢,下面分別說明各部分:

  • db.session.query(Post):指明這個查詢表要返回(Post)對象
  • select_from(Follow)的意思是這個查詢從Follow模型開始
  • filter_by(follower_id=self.id)使用關注用戶過濾follows表
  • john(Post, Follow.followed_id == Post.author_id)聯結filter_by()得到的結果和Post對象

調換過濾器和聯結的順序可以簡化這個查詢:

return Post.query.john(Follow, Follow.followed_id == Post.author_id)\
    .filter(Follow.follower_id == self.id)

如果首先執行聯結操作,那麼這個查詢就可以從Post.query開始,此時唯一需要使用的兩個過濾器是john()filter(),但這兩種查詢是一樣的嗎?先執行聯結操作再過濾看起來工作量會更大一些,但實際上這兩種查詢是等效的,SQLAlchemy首先收集所有的過濾器,然後再以最高效的方式生成查詢,這兩種查詢生成的原生SQL指令是一樣的,我們要把後一種查詢寫入Post模型,如下:

class User(db.Model):

    #...

    @property
    def followed_posts(self):
        return Post.query.join(Follow, Follow.followed_id == Post.author_id)\
            .filter(Follow.follower_id == self.id)   

followed_posts()方法定義爲屬性,因此調用時無需加(),如此一來所有關係的句法都一樣了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章