创建博客-完善关注功能(2)

使用数据库联结查询所关注用户的文章

程序首页目前按时间降序显示数据库中的所有文章,现在我们已经完成了关注功能,如果让用户选择只查看所关注用户发布的博客文章就更好了

若想显示所关注用户发布的所有文章,第一步显然先要获取这些用户,然后获取各用户的文章,再按一定顺序排列,写入单独列表,可是这种方式的伸缩性不好,随着数据库不断变大,生成这个列表的工作量也不断增长,而且分页等操作也无法高效率完成,获取博客文章的高效方式是只用一次查询

完成这个操作的数据库操作称为联结,联结操作用到两个或更多的数据表,在其中查找满足指定条件的记录组合,再把记录组合插入一个临时表中,这个临时表就是联结查询的结果,理解联结查询的最好方式是实例讲解

下表是一个users表实例,表中有3个用户
这里写图片描述

下表是对应的posts表,表中有几篇博客文章
这里写图片描述
最后,下面follows表显示了谁关注谁,从这个表中你可以看出,john关注了david,susan关注了john,但david谁也没关注
这里写图片描述

若想获得susan所关注用户发布的文章,就要合并posts表和follows表,首先过滤follows表,只留下关注者为susan的记录,即上表中的最后两行,然后过滤posts表,留下author_id和过滤后的follows表中followed_id相等的记录,把两次过滤结果合并,组成临时联结表,这就能高效查询susan所关注用户的文章列表,下表是联结操作的结果,表中用来执行链接操作的*标记:

idauthor_id*bodyfollowed_idfollowed_id*
21john的博客文章21
33david的博客文章23
41john的第二篇博客文章21

这个表中包含的博客文章都是用户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()方法定义为属性,因此调用时无需加(),如此一来所有关系的句法都一样了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值