Flask狼书笔记 | 09_图片社交网站 - 大型项目的架构与需求(2)

简介: 9.8 收藏图片前面已经学习过如何使用关联表来表示多对多关系,缺点是只能表示关系,不能存储数据(如我还想记录下收藏图片的时间戳)。这种情况下,我们可以使用关联模型来表示多对多关系。在关联模型中,我们将Photo模型与User模型的多对多关系,分离成了User模型和Collect模型的一对多关系,和Photo模型与Collect模型的一对多关系。

Flask狼书笔记 | 09_图片社交网站 - 大型项目的架构与需求(1):https://developer.aliyun.com/article/1407226

9.8 收藏图片

前面已经学习过如何使用关联表来表示多对多关系,缺点是只能表示关系,不能存储数据(如我还想记录下收藏图片的时间戳)。这种情况下,我们可以使用关联模型来表示多对多关系。

在关联模型中,我们将Photo模型与User模型的多对多关系,分离成了User模型和Collect模型的一对多关系,和Photo模型与Collect模型的一对多关系。

5c75a9b688754dbaba378dd7d17ba5e7.png

不过,在使用了关联模型后,Photo和User模型中的关系属性(relationship)返回的不再是关系另一侧的记录,而是关系的中间人——Collect记录。需要进一步调用collector和collected才会加载对应的用户和图片对象。

class Collect(db.Model):
 ...
 collector_id = db.Column(db.Integer, db.ForeignKey(user.id), primary_key=True)
 collected_id = db.Column(db.Integer, db.ForeighKey(photo.id), primary_key=True)
 collector = db.relationship('User', back_populates='collections', lazy='joined')
 collected = db.relationship('Photo', back_populates='collectors', lazy='joined')
class User(db.Model):
 ...
 collections = db.relationship('Collect', back_populates='collectors', cascade='all')
class Photo(db.Model):
 ...
 collectors = db.relationship('Collect', back_populates='collected', cascade='all')


9.9 用户关注

和图片收藏一样,用户关注也是多对多的关系,我们同样希望可以记录关注行为的时间戳,因此仍然使用关系模型来表示多对多关系。但不同之处在于,关注关系的两侧都在同一个模型User中,这种关系被称为自引用关系

我们不妨令关注关系为Follow,则在Follow模型上建立反向关系时,SQLAlchemy没法知道哪个外键对应哪个反向属性,需要在关系函数中使用foreign_keys参数来明确对应的字段。(p366)


感觉这一段很绕!


补充:如果对关系属性设置了dynamic类型的加载方式,调用关系属性会返回查询对象,此时可以进行进一步的过滤操作。事件绑定

前面提到了用户资料弹窗,我们希望在用户资料弹窗中也有一个关注按钮,但jQuery中,on()以及快捷方法click()hover()等事件处理器只能绑定到已经存在的元素,所以不能通过弹窗元素的id作为选择器,如

$('.follow-btn').on(...)

有两种解决方式:

  1. 在html元素中使用onclick属性指定调用的目标函数(即行内JavaScript),但不推荐。
  2. 监听整个DOM:
$(document).on('click', '.follow-btn', follow.bind(this));

这里on()方法的三个参数分别是:事件,选择器,触发的回调函数。


AJAX请求下的错误消息


因为AJAX请求异步发送,不会重载页面,因此不能使用flash()发送消息。我们可以在视图中返回包含提示消息的json响应,并使用jquery提供的ajaxError()方法设置一个统一的ajax错误回调函数。(p377)

9.10 消息提醒

我们希望未读消息数是实时更新显示的,而不是需要手动刷新一次页面才能看到新的数据。这个功能可以通过轮询实现,即每隔一段事件自动发出一个ajax请求。在JavaScript中,使用setInterval()方法可以周期性地按照时间间隔不停地执行代码,见(p384)。

9.11用户资料与账户设置

前面介绍了如何为用户生成随机的头像,但作为一个社交程序,我们希望可以使用自己喜欢的图片作为自己的头像。Flask-Avatars通过集成jQuery插件Jcrop(需要在模板中加载对应的资源文件)提供了裁剪头像的支持。(p387)


实现自定义头像的功能需要两个表单,一个用于单纯的上传图片,另一个用于保存裁剪图片的坐标。


修改密码(疑惑)


书中修改密码增加了“新鲜的”标记判断,据说通过“使用session对象写入名为_fresh的cookie实现”。但登录状态和是否新鲜这两个字段不都是写在session对象中吗?怎么能够判断“虽然用户仍然保持登录状态,但会话已经被标记为不新鲜”?

9.12 首页与探索

我们希望在首页可以看到自己关注的用户最近发布的图片,这个查询包含以下步骤:(p399)

  1. 获取用户关注的所有用户
  1. 获取每个用户发布的图片
  2. 使用时间降序排列这些图片

这里有两种实现方式:子查询联结,通常来说联结的效率更高。

# 子查询
followed_ids = db.session.query(Follow.followed_id).
  filter(Follow.follower_id == current_user.id).subquery()
# 主查询
followed_photos = Photo.query.filter(Photo.author_id.in_(followed_ids)).
  order_by(Photo.timestamp.desc()).all()
# 联结查询
Photo.query.join(Follow, Follow.followed_id == Photo.author_id)
  .filter(Follow.follower_id == current_user.id)

联结查询的代码也显得更加简洁。

9.13 使用Flask-Whooshee实现全文搜索

我们生活中常见的各种网站,基本上都会提供一个搜索框,大多数数据库引擎本身也提供了全文搜索的功能。但如果你希望实现的是一个不局限于某个数据库引擎的搜索引擎,可以考虑使用集成了Whoosh的Flask-Whooshee扩展,它同时也与SQLAlchemy扩展进行了集成。


全文搜索的原理:索引程序通过扫描数据库中的每一个词,对每一个词建立一个索引,指明它出现的次数和位置。

from albumy.extensions import whooshee
@whooshee.register_model('username', 'name')
class User(db.Model):
    ...

索引默认会在写入相应的字段后,自动更新。你也使用reindex()方法可以重建索引:

whooshee.reindex()

对于写入频繁的程序,最好关闭索引的自动更新,使用定时任务工具周期性手动地重建(更新)索引。关于定时任务工具,你可以考虑使用Celery,或者扩展Flask-APScheduler。

使用搜索

User.query.whooshee_search(q).all() # q为想要搜索的字符串

9.14 编写网站后台

对于一个真实的程序来说,后台管理可能会包含以下内容:

  1. 用户行为分析
  2. 网站访问统计
  3. 内容过滤与关键词审核
  1. 推送系统消息
  2. 编辑推荐内容
  3. 网站固定内容编辑
  4. 数据库在线操作

书中只实现了对于用户和资源(发布内容、评论等)的关系,实现比较简单,不再介绍。

小记

这一章真的非常非常的长,在书中有100多页。虽然我现在已经将这一部分看完了,但是自己用来边做边学的玩具项目却没有跟上。不知道这些新鲜的知识会不会很快就从我的脑海里消逝。

啃砖头书确实也是一件比较有成就感的事情。身边有朋友说感觉看书很浪费时间,有很多东西根本没必要去看。但是,网站上的一些视频或文档教程常常让我感觉,一半好像知道了,一半却直入云里雾里。还是砖头的作者更有耐心。比如,即使我没有学习过javascript,书中的解释也可以使我基本明白代码的意思。(也仍是一件需要好好权衡的事情,毕竟看书会很花时间)。


为什么会学习flask呢?我并没有对依靠它寻找工作抱有希望,Web开发已经卷疯了。它相对简单易学,我可以使用它尝试做一些自己的小工具,希望会对我的学习生活起到一些帮助作用。


在写笔记的过程中,也在继续慢慢地学习如何写笔记。记下需要注意的、容易出错的地方?记下主要的流程和思路?总之,还有很长的路要走。


相关文章
|
8天前
|
XML 前端开发 Android开发
Kotlin教程笔记(80) - MVVM架构设计
Kotlin教程笔记(80) - MVVM架构设计
|
11天前
|
前端开发 JavaScript 测试技术
android做中大型项目完美的架构模式是什么?是MVVM吗?如果不是,是什么?
在 Android 开发中,选择合适的架构模式对于构建中大型项目至关重要。常见的架构模式有 MVVM、MVP、MVI、Clean Architecture 和 Flux/Redux。每种模式都有其优缺点和适用场景,例如 MVVM 适用于复杂 UI 状态和频繁更新,而 Clean Architecture 适合大型项目和多平台开发。选择合适的架构应考虑项目需求、团队熟悉度和可维护性。
39 6
|
11天前
|
存储 前端开发 数据可视化
在实际项目中,如何选择使用 Flux 架构或传统的 MVC 架构
在实际项目中选择使用Flux架构或传统MVC架构时,需考虑项目复杂度、团队熟悉度和性能需求。Flux适合大型、高并发应用,MVC则适用于中小型、逻辑简单的项目。
|
20天前
|
前端开发 JavaScript 测试技术
Android适合构建中大型项目的架构模式全面对比
Android适合构建中大型项目的架构模式全面对比
39 2
|
21天前
|
XML 前端开发 Android开发
Kotlin教程笔记(80) - MVVM架构设计
Kotlin教程笔记(80) - MVVM架构设计
24 1
|
29天前
|
XML 前端开发 Android开发
Kotlin教程笔记(80) - MVVM架构设计
本系列学习教程笔记详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。对于希望快速学习Kotlin语法的读者,建议参考“简洁”系列教程。本文重点介绍了Kotlin实现MVVM架构的设计思路和代码实现,包括Model、ViewModel和View层的具体实现,以及如何通过LiveData和viewModelScope有效管理数据和内存,避免内存泄漏。此外,还讨论了MVVM架构的常见缺点及应对策略,帮助开发者在实际项目中更好地应用这一设计模式。
32 1
|
22天前
|
缓存 前端开发 JavaScript
前端架构思考:代码复用带来的隐形耦合,可能让大模型造轮子是更好的选择-从 CDN 依赖包被删导致个站打不开到数年前因11 行代码导致上千项目崩溃谈谈npm黑洞 - 统计下你的项目有多少个依赖吧!
最近,我的个人网站因免费CDN上的Vue.js包路径变更导致无法访问,引发了我对前端依赖管理的深刻反思。文章探讨了NPM依赖陷阱、开源库所有权与维护压力、NPM生态问题,并提出减少不必要的依赖、重视模块设计等建议,以提升前端项目的稳定性和可控性。通过“left_pad”事件及个人经历,强调了依赖管理的重要性和让大模型代替人造轮子的潜在收益
|
29天前
|
存储 前端开发 Java
Kotlin教程笔记 - MVVM架构怎样避免内存泄漏
Kotlin教程笔记 - MVVM架构怎样避免内存泄漏
|
3天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
2天前
|
Dubbo Java 应用服务中间件
服务架构的演进:从单体到微服务的探索之旅
随着企业业务的不断拓展和复杂度的提升,对软件系统架构的要求也日益严苛。传统的架构模式在应对现代业务场景时逐渐暴露出诸多局限性,于是服务架构开启了持续演变之路。从单体架构的简易便捷,到分布式架构的模块化解耦,再到微服务架构的精细化管理,企业对技术的选择变得至关重要,尤其是 Spring Cloud 和 Dubbo 等微服务技术的对比和应用,直接影响着项目的成败。 本篇文章会从服务架构的演进开始分析,探索从单体项目到微服务项目的演变过程。然后也会对目前常见的微服务技术进行对比,找到目前市面上所常用的技术给大家进行讲解。
11 1
服务架构的演进:从单体到微服务的探索之旅