参考外文博客:https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-viii-followers

这章将学习如何实现类似于Twitter和其他社交网络的“粉丝”或“关注”,比如关注你。

接下来,将更多介绍应用程序的数据库。让用户能够轻松选择Ta们想要关注的其他用户。因此,将扩展数据库,以便跟踪谁在关注(粉)谁。

再次学习数据库关系

我想每一个用户维护一个“关注”和“关注者”列表。不幸的是,关系数据库没有我能用于这些列表的列表类型,所有都有记录、这些记录之间的关系。

数据库中有一个表示用户的表,所以剩下的是提出可以为关注、关注者链接建模的正确关系类型。现在是学习基本数据库关系类型的好时机:

一对多

通过这个关系连接的两个实体分别是用户,帖子。一个用户有很多篇帖子,每个帖子有一个用户。在数据库中,这个关系多侧使用外键。在上述关系中,外键user_id字段添加到posts表中。这个字段将每个帖子连接到user表中其作者的记录。

明显地,user_id字段提供了对给定帖子作者的直接访问,但反过来,为使得关系有用,我们应该可以获得给定用户所编写的帖子列表。posts表user_id字段也足以回答此问题,因为数据库中具有允许有效查询的索引,如 【检索user_id为X的所有帖子】

多对多

多对多关系有点复杂。例如,考虑一个拥有studentsteachers的数据库,可以说一个学生有很多个老师,一个老师有很多个学生。这就像来自两端的两个重叠的一对多关系

对于这种类型的关系,我们应该能够查询到数据库,并取得教授给定学生的教师列表、教师班级的学生列表。这在关系数据库中表示实际上并不重要,因为无法通过向现有表添加外键来完成。

虽然一开始可能看起来不太明显,但是具有两个外键的关联表 能够有效地回答关于多对多关系的所有查询。

多对一,一对一

多对一关系,类似于一对多关系。不同之处在于从“多”侧看这种关系。

一对一关系是一对多关系的特殊情况。表示是类似的,但是得向数据库添加约束以防止“多”侧具有多个链接。虽然在某些情况下,这种关系很有用,但并不像其他关系类型常见。

选用的模型,很容易确定跟踪关注者的正确数据模型是多对多关系。因为一个用户可以关注很多用户,而一个用户也可以被很多用户所关注。在学生、教师的案列中,我们通过多对多关系关联这两个实体。但在关注案列下,我有用户关注其他用户,所以只有用户。那么多对多关系的第二个实体是什么?

关系的第二个实体也是用户。将类的实例链接到同一个类的其它实例的关系称为自引用关系。这将是我们在此所拥有的

下面是跟踪关注者的自引用 多对多关系的图表

followers表中是关系的关联表,表中外键都指向user表中的行,因为它将用户链接到用户。这个表中每一个记录表示关注者用户,被关注用户之间的一个链接。如同学生,教师的案例,像这样的设置允许数据库回答有关我们将要解决的关注,关注用户的所有问题

用数据库模型表示自关联关系

首先,在数据库中添加关注者 followers,下方是followers关联表:

上述代码是上一节【跟踪关注者的自引用 多对多关系的图表】的的直接翻译了。不过,注意,这里没有声明这个表为模型,即如user表、post表那样。由于这是一个除了外键而没有其他数据的辅助表,因此在没有关联模型类的情况下创建了这个表。

现在,可在user表中声明多对多关系。这个关系将User实例 链接到其他User实例,因此作为约定,假设通过此关系链接到一对用户,左侧用户 关注 右侧用户。我们在左侧用户中定义了 followed 的关系,因为当我们从左侧查询这个关系时,将得到已关注的用户列表(即 右侧用户)。下方逐个检查db.relationship()的所有参数:

  1. User 是关系的右侧实体(左侧是父类)。由于这是一种自引用关系,我必须在两边使用相同的类。
  2. secondary 配置用于这个关系的关联表,就是在这个类上定义的关联表 followers
  3. primaryjoin指定了左侧实体(关注者)与关联表链接的条件。关系左侧的连接条件是与关联表中follower_id字段匹配的用户ID。follwer.c.follower_id表达式引用了关联表中follower_id列。
  4. secondaryjoin指定了右侧实体(被关注者)与关联表链接的条件。这个条件与primaryjoin类似,唯一不同的是:现在使用的followed_id,它是关联表中的另一个外键。
  5. backref定义如何右侧实体访问这个关系。从左侧开始,关系被名称为 followed,因此右侧将使用名称followers来表示链接到右侧目标用户的所有左侧用户。附加lazy 参数表示这个查询的执行模式,设置为dynamic模式的查询在特定请求之前不会运行,这也是我们设置帖子的一对多关系。
  6. lazy类似于同名参数backref,但这个适用于左侧查询而不是右侧。

由于SQLAlchemy ORM,一个用户关注另一用户 的行为 能被以followed 关系如同是一个列表一样 记录在数据库中,例如,假如我有两个用户存储在 user1 和 user2变量中,我能够用这个简单语句表示 第一个用户关注第二个用户:

尽管关注、取消关注 很容易,但我们希望在代码中提升可重用性,因此我们不会在代码中使用 “appends”、“removes”。代替的方法是,我们将在User模型中实现“follow”和“unfollow”方法。最后是将应用程序逻辑从视图函数移到模型或其他辅助类或模块中,因为正如在本章看到的,这让单元测试会变得更容易。

下方User模型中添加,删除关系的更改:

follow()unfollow()方法用了正如上所展示的关系对象的append()remove()方法,但是在它们接触这个关系之前,它们用了 is_following()辅助方法以确保请求动作是有道理的。例如,假如要求 user1 关注user2,但事实证明在数据库中已经存在这个关注关系,就不必重复了。相同的逻辑同样运用到 取消关注。

is_following()方法在followed关系中发出一个查询去检查两个用户是否已存在链接。在之前看到 使用SQLAlchemyfilter_by()方法去查询对象,例如 查找给定username的用户。在这用到的filter()方法是类似的,但是低水平,因为它能包含任意过滤条件,不像filter_by()只能检查与常量值的相等性。在is_following()中我们正在使用的条件 查找关联表中的项目,左侧外键设置为self 用户,右侧设置为 user参数。查询以一个count()方法终止,该方法返回结果数。这个查询结果将是0 或1,因此检查计数为1 或大于0实际上是等效的。过去使用的前提查询终止符是all()、first()。

获取已关注用户的帖子

对数据库中的关注者的支持几乎已经完成,但实际上还缺少一个重要的功能。在应用程序的`index`页面,将显示已登录用户所关注的其他所有用户的帖子,因此,我们需要提供一个返回这些帖子的数据库查询。

最明显解决方案是 运行一个返回已关注用户列表的查询,正如我们已知道的,它就是 user.followed.all()。接着,对这些返回的每个用户,我们运行查询取得帖子。一旦我们有了帖子,就将它们合并到一个列表,并按日期对它们进行排序。听起来是这样,其实不是!

这种方法有几个问题。假如一个用户关注了1000人,会发送什么?那么我得执行1000此数据库查询来收集所有帖子。接着需要合并、排序内存中的1000个列表。第二个问题,考虑到应用程序的主页最终将实现分页,因此它不会显示所有可用帖子,仅是前几个,如果需要,可用一个链接去取得更多。第三个问题,如果要按日期排序显示帖子,如何知道哪些用户帖子才是所有用户中最新的?除非我得到所有帖子并先排序。这实际上是一个不能很好扩展的糟糕解决方案。

实际上并没有办法避免博客帖子的合并、排序,但在应用程序中执行会导致一个非常低效的过程。这类工作是关系数据库最擅长的。数据库具有索引,允许它以更有效的方式执行查询、排序。因此,我们真正想要的是提出一个简单的数据库查询,它定义了我们想要取得的信息,然后让数据库找出如何以最有效的方式提取信息。

这是在这个应用程序中使用的最复杂的查询了。这个查询结构有3个主要部分 join()filter()order_by(),都是SQLAlchemy中查询对象的方法。

联合查询介绍

要理解 join 操作的作用,先看一个例子。假设我有一个User表,包含以下内容:

简单起见,我们不显示 用户模型中的所有字段,只显示对这个查询的重要字段。假设 followers 关联表 表示用户john正在关注用户susan和david,用户susan正在关注用户mary,用户mary正在关注david。表示这个内容的数据是:

最后,posts表 包含每个用户的一条帖子

这个表还省略了一些不属于本讨论范围的字段。

这是我为这个查询再次定义的join()

上述代码正在posts表上调用join 操作。第一个参数是关注者关联表;第二个参数是连接条件。我希望数据库创建一个临时表,此表结合了posts表followers表的数据。这个数据将根据我作为参数传递的条件进行合并。

使用的条件是followers表followed_id字段 必须等于 posts表user_id字段。要执行此合并,数据库将从posts表(join 的左侧)获取每个记录,并附加followers表(join 的右侧)中匹配条件的所有记录。

如果followers表中有多个记录符合条件,则每个记录条目将重复。如果对于给定的帖子在followers表没有匹配,那么这个帖子记录不会join操作结果中。

注意,在所有情况下,user_id和followed_id列是相等的,这是因为连接条件。来自用户john的帖子没有出现在上述连接表中,是因为被关注者中没有包含用户john,换句话说,没有任何人关注john。而来自用户david的帖子出现了两次,因为这个用户有个关注者。

虽然创建了join操作,但暂时并未得到想要的结果。请继续,这只是更大查询的一部分

过滤

join操作给我一个所有被关注用户的帖子的列表,远超出我真正想要的那部分数据。我只对这个列表的一个子集感兴趣,即某个用户关注的用户们的帖子。因此,我需要调用filter()来去掉不需要的数据。

由于这个查询是位于User类中的方法,因此self.id 表达式引用了我感兴趣的用户的用户ID。filter()选择join表中follower_id等于这个ID的行,换句话说,我只保留follower是这个用户的数据。

这些才是我想要的帖子。

记住,查询是从Post类发出的,所以即使我最终得到了由数据库创建的一个临时表来作为查询的一部分,但结果是包含在此临时表中的帖子,并没有额外的列是由join操作添加的。

在此,希望结果是按帖子的时间戳字段按降序排序的。通过这个排序,第一个结果将是最新的博客帖子。

结合自己和关注者的帖子

followed_posts()函数中使用的查询非常有用,但有一限制。人们希望看到自己的帖子也包含在Ta所关注的用户帖子的时间线中,不过这个查询目前还未建立。

有两种方法可扩展此查询以包含用户自己的帖子。最直接的方法是保持查询变量,但要确保所有用户都关注自己。如果你是自己的关注者,那么上面显示的查询将会找到你自己的帖子,以及你关注的所有人帖子。这种方法的缺点是它会影响关于关注者的统计数据。所有的关注者数量都会被加1,所以必须在显示之前进行调整。第二个方法是通过创建第二个查询,返回用户自己的帖子,然后使用 union 运算符 将这两个查询合并为一个查询。

在考虑了这两个选项后,决定选择第二个方法。下方将看到followed_posts()扩展后的功能,通过一个 union 包含用户自己的帖子:修改代码

在应用程序中添加两个新路由,以关注、取消关注一个用户:

app/routes.py:关注、取消关注用户的路由

现在有了视图函数,就可以从应用程序中的页面链接到它们了。在每个用户的个人资料页面中添加链接以关注、取消关注用户:

app/rtemplates/user.html:在用户个人资料页面中添加 关注、取消关注的链接

对用户个人资料页面更改:一是 在最近访问的时间戳下添加一行,以显示该用户拥有多少关注者和关注用户。二是当查看自己的个人资料页时,出现的“Edit”链接,可能会变成下方3种链接之一:

  1. 如果用户正在查看自己的个人资料页,那么“Edit”链接跟以前一样显示;
  2. 如果用户正在查看当前未关注的用户,则会显示“Follow”链接;
  3. 如果用户正在查看当前关注的用户,则会显示“Unfollow”链接。

此时,运行应用程序,创建一些用户并测试 关注、取消关注用户的功能。

唯一需要记住的是,键入要关注 或取消关注的用户的个人资料页面的URL,因为目前无法查看用户列表。例如,如果要关注 susan,则可在浏览器地址栏输入:http://localhost:5000/user/susan,就能访问该用户的个人资料页。确保在测试关注、取消关注时,检查关注、关注者的数量变化情况。

flask入门和进阶五(关注功能的实现Followers)相关推荐

  1. 玩转数据结构从入门到进阶五

    下载地址:https://pan.baidu.com/s/1k_D0a1sGjShw8JCR4lUKpg    提取密码:6666

  2. python flask快速入门与进阶 百度云_Python Flask快速入门与进阶

    课程目录 1-1 Python Flask快速入门与进阶.mp4 2-1 windows环境安装开发环境 (上).mp4 2-2 windows环境安装开发环境 (下).mp4 2-3 配置开发环境. ...

  3. android自定义美颜相机完整程序,Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机...

    源码链接:https://github.com/smzhldr/AGLFramework 一.前言 商店里有数十款的美颜相机类产品,其实现原理基本上都是以OpenGL ES为核心的特效处理,大神可以忽 ...

  4. flask web开发是前端还是后端_Flask Web开发实战:入门、进阶与原理解析 PDF 全格式版...

    给大家带来的一篇关于Flask相关的电子书资源,介绍了关于Flask.Web.开发实战方面的内容,本书是由机械工业出版社出版,格式为PDF,资源大小12.2M,李辉编写,目前豆瓣.亚马逊.当当.京东等 ...

  5. android 美颜相机开发,Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机...

    源码链接:https://github.com/smzhldr/AGLFramework 一.前言 商店里有数十款的美颜相机类产品,以及像抖音,唱吧之类带有视频的软件,功能很强大,其实现原理基本上都是 ...

  6. 《Flask Web开发实战:入门、进阶与原理解析》读书笔记

    写在前面 学docker编排,有一个用Flask框架的Demo,感觉挺方便,所以学习下 基于<Flask Web开发实战:入门.进阶与原理解析>做的读书笔记 个人还是比较喜欢看书,看书的话 ...

  7. Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机

    源码链接:https://github.com/smzhldr/AGLFramework 基础知识入门篇(Hello Triangle) 渲染纹理到屏幕 GLSurfaceView预览相机 简单易用的 ...

  8. python flask快速入门与进阶-Flask基础进阶与python flask实战bbs教程

    ├─Flask基础进阶 │ 01-HTTP 基础知识.mp4 │ 02-python CGI 与 WebServer.mp4 │ 03-virtuanenv配置及Flask快速示例.mp4 │ 04- ...

  9. python入门与进阶

    title: python入门与进阶 categories: python tags: [python] python入门导学 python的特点 是面向对象的编程语言 简介,灵活,优雅,哲学 易于上 ...

最新文章

  1. js经典校验之注册与登录校验
  2. 亿级流量电商详情页系统实战:缓存架构+高可用服务架构+微服务架构
  3. 周报措辞规范(周报规范用语、不规范用语)
  4. 5行Python就能爬取 3000+ 上市公司的信息?
  5. 从零开始学python人工智能课程_从零开始如何学习人工智能?
  6. 查看目标主机安装的杀毒软件
  7. windows平台下vlc编译
  8. 计算两个日期相差的天数,Calendar用法
  9. linux 源码安装node 9,linux如何安装node?
  10. ADB工具安装及常用命令
  11. Firefox扩展IE Tab Plus内置功能导致浏览所有网页加载superfish.com脚本
  12. 【围棋棋盘绘制——html实现】
  13. 分布式调度框架大集合
  14. 乔春洋:品牌文化的三大内涵
  15. 第6回 スライドによるページナビゲーション
  16. python开发工程师是干嘛的-python开发工程师是做什么的
  17. 教师节HTML祝福网页,教师节祝福信息模板
  18. Django SVG 名字空间
  19. 微软官方制作纯净版的U盘启动盘(详细步骤)
  20. ...mapMutations的使用

热门文章

  1. C语言之打印错误信息
  2. 【Apache NIFI 翻译】2-Getting Started with Apache NiFi 入门
  3. IxChariot测试网络设备性能
  4. Java实现 kiosk模式,java – 使用“kiosk模式”创建Phonegap应用程序
  5. matlab非单位阶跃响应,MATLAB下二阶系统的单位阶跃响应
  6. 使用GO实现尚硅谷家庭记账系统
  7. 小丁带你走进git的世界三-撤销修改(转)
  8. 计算机病毒结构及技术分析
  9. 【渝粤题库】陕西师范大学204001英语写作 作业(高起本、专升本)
  10. python凯撒密码流程图_凯撒移位密码加密算法的Python3.0实现方法