Flask Web开发笔记

Flask笔记

2.1初始化

Web 服务器使用一种名为 Web 服务器网关接口
(Web Server Gateway Interface,WSGI)的协议,把接收自客户端的所有请求都转交给这个对象处理。程序实例是 Flask 类的对象

2.2 路由和视图函数

程序实例需要知道对每个 URL 请求运行哪些代码,所以保存了一个URL到
Python 函数的映射关系。处理 URL 和函数之间关系的程序称为路由。

在 Python 代码中嵌入响应字符串会导致代码难以维护

2.3启动服务器

name=='main' 是 Python 的惯常用法,在这里确保直接执行这个脚本时才启动开发Web 服务器。如果这个脚本由其他脚本引入,程序假定父级脚本会启动不同的服务器,因此不会执行 app.run()。

服务器启动后,会进入轮询,等待并处理请求。轮询会一直运行,直到程序停止,比如按Ctrl-C 键。

2.5请求-响应循环
2.5.1 程序和请求上下文

Flask 使用上下文临时把某些对象
变为全局可访问。

变量名 上下文 说明
current_app 程序上下文 当前激活程序的程序实例
g 程序上下文 处理请求时用作临时存储的对象。每次请求都会重设这个变量
request 请求上下文 请求对象,封装了客户端发出的
session 请求上下文 用户会话,用于存储请求之间需要“记住”的值的词典
2.5.2 请求调度

程序收到客户端发来的请求时,要找到处理该请求的视图函数。为了完成这个任务,Flask
会在程序的 URL 映射中查找请求的 URL。URL 映射是 URL 和视图函数之间的对应关系。
Flask 使用 app.route 修饰器或者非修饰器形式的 app.add_url_rule() 生成映射。

2.5.3 请求钩子

有时在处理请求之前或之后执行代码会很有用

  • before_first_request:注册一个函数,在处理第一个请求之前运行。
  • before_request:注册一个函数,在每次请求之前运行。
  • after_request:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。
  • teardown_request:注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行。
2.5.4 响应

Flask 调用视图函数后,会将其返回值作为响应的内容。大多数情况下,响应就是一个简
单的字符串,作为 HTML 页面回送客户端。

但 HTTP 协议需要的不仅是作为请求响应的字符串。HTTP 响应中一个很重要的部分是状
态码,Flask 默认设为 200,这个代码表明请求已经被成功处理。

3.1 Jinja2模板引擎

3.1.1 渲染模板

Flask 提供的 render_template 函数把 Jinja2 模板引擎集成到了程序中。render_template 函
数的第一个参数是模板的文件名

3.1.2 变量

在模板中使用的 {{ name }} 结构表示一个变量,它是一种特殊的占位符,告诉模
板引擎这个位置的值从渲染模板时使用的数据中获取。

Jinja2 能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象。在模板

可以使用过滤器修改变量,过滤器名添加在变量名之后,中间使用竖线分隔。例如,下述
模板以首字母大写形式显示变量 name 的值:
Hello, {{ name|capitalize }}

3.1.3 控制结构

下面这个例子展示了如何在模板中使用条件控制语句:

{% if user %}
 Hello, {{ user }}!
{% else %}
 Hello, Stranger!
{% endif %}

另一种常见需求是在模板中渲染一组元素。下例展示了如何使用 for 循环实现这一需求:

 <ul>
 {% for comment in comments %}
 <li>{{ comment }}</li>
 {% endfor %}
 </ul>

Jinja2 还支持宏。宏类似于 Python 代码中的函数。

需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免
重复:

{% include 'common.html' %}
3.2 使用Flask-Bootstrap集成Twitter Bootstrap

Bootstrap(http://getbootstrap.com/)是 Twitter 开发的一个开源框架,它提供的用户界面组
件可用于创建整洁且具有吸引力的网页,而且这些网页还能兼容所有现代 Web 浏览器。

3.3 自定义错误页面

像常规路由一样,Flask 允许程序使用基于模板的自定义错误页面。最常见的错误代码有
两个:404,客户端请求未知页面或路由时显示;500,有未处理的异常时显示。为这两个
错误代码指定自定义处理程序的方式如示例 3-6 所示。

@app.errorhandler(404)
def page_not_found(e):
 return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
 return render_template('500.html'), 500

3.4 链接
在模板中直接编写简单路由的 URL 链接不难,但对于包含可变部分的动态路由,在模板
中构建正确的 URL 就很困难。而且,直接编写 URL 会对代码中定义的路由产生不必要的
依赖关系。如果重新定义路由,模板中的链接可能会失效。

为了避免这些问题,Flask 提供了 url_for() 辅助函数,它可以使用程序 URL 映射中保存的信息生成 URL。

3.5 静态文件

默认设置下,Flask 在程序根目录中名为 static 的子目录中寻找静态文件。如果需要,可在static 文件夹中使用子文件夹存放文件。

3.6 使用Flask-Moment本地化日期和时间

服务器需要统一时间单位,这和用户所在的地理位置无关,所以一般使用协调世界时
(Coordinated Universal Time,UTC).不过用户看到 UTC 格式的时间会感到困惑,他们更希望看到当地时间,而且采用当地惯用的格式。

一个优雅的解决方案是,把时间单位发送给 Web 浏览器,转换成当地时间,然后渲染。

4.1 跨站请求伪造保护

默认情况下,Flask-WTF 能保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,
CSRF)的攻击。恶意网站把请求发送到被攻击者已登录的其他网站时就会引发 CSRF 攻击。

为了实现 CSRF 保护,Flask-WTF 需要程序设置一个密钥。Flask-WTF 使用这个密钥生成
加密令牌,再用令牌验证请求中表单数据的真伪。设置密钥的方法如示例 4-1 所示。

4.2 表单类

使用 Flask-WTF 时,每个 Web 表单都由一个继承自 Form 的类表示。这

4.3 把表单渲染成HTML

表单字段是可调用的,在模板中调用后会渲染成 HTML。假设视图函数把一个 NameForm 实例通过参数 form 传入模板,在模板中可以生成一个简单的表单,如下所示:

<form method="POST">
 {{ form.hidden_tag() }}
 {{ form.name.label }} {{ form.name() }}
 {{ form.submit() }}
</form>

4.4 在视图函数中处理表单

不仅要渲染表单,还要接收表单中的数据

4.5 重定向和用户会话

程序可以把数据存储在用户会话中,在请求之间“记住”数据。用户会话是一种私有存储,存在于每个连接到服务器的客户端中

4.6 Flash消息

请求完成后,有时需要让用户知道状态发生了变化。这里可以使用确认消息、警告或者错误提醒。

仅调用 flash() 函数并不能把消息显示出来,程序使用的模板要渲染这些消息。最好在基模板中渲染Flash 消息,因为这样所有页面都能使用这些消息。Flask 把get_flashed_messages() 函数开放给模板,用来获取并渲染消息

5.1 SQL数据库

关系型数据库把数据存储在表中,表模拟程序中不同的实体。

表的列数是固定的,行数是可变的。列定义表所表示的实体的数据属性。

表中有个特殊的列,称为主键,其值为表中各行的唯一标识符。表中还可以有称为外键的列,引用同一个表或不同表中某行的主键。行之间的这种联系称为关系,这是关系型数据库模型的基础。

5.2 NoSQL数据库

所有不遵循上节所述的关系模型的数据库统称为 NoSQL 数据库。

使用 NoSQL 数据库当然也有好处。数据重复可以提升查询速度。列出用户及其角色的操作很简单,因为无需联结

5.3 使用SQL还是NoSQL

SQL 数据库擅于用高效且紧凑的形式存储结构化数据。这种数据库需要花费大量精力保证数据的一致性。NoSQL 数据库放宽了对这种一致性的要求,从而获得性能上的优势。

5.4 Python数据库框架

Flask 并不限制你使
用何种类型的数据库包,因此可以根据自己的喜好选择使用 MySQL、Postgres、SQLite、Redis、MongoDB 或者 CouchDB。

  1. 易用性
  2. 性能
  3. 可移植性
5.5 使用Flask-SQLAlchemy管理数据库

Flask-SQLAlchemy 是一个 Flask 扩展,简化了在 Flask 程序中使用 SQLAlchemy 的操作。

5.6 定义模型

模型这个术语表示程序使用的持久化实体。

5.7 关系

关系型数据库使用关系把不同表中的行联系起来。

5.8 数据库操作
5.8.1 创建表

方法是使用 db.create_all()

5.8.2 插入行

db.session.add(admin_role)

5.8.3 修改行

db.session.add(admin_role)
db.session.commit()

5.8.4 删除行

db.session.delete(mod_role)
db.session.commit()

5.8.5 查询行

Flask-SQLAlchemy 为每个模型类都提供了 query 对象

5.9 在视图函数中操作数据库
5.10 集成Python shell

每次启动 shell 会话都要导入数据库实例和模型,这真是份枯燥的工作。为了避免一直重复导入,我们可以做些配置,让 Flask-Script 的 shell 命令自动导入特定的对象。

5.11 使用Flask-Migrate实现数据库迁移
7.1 项目结构

多文件 Flask 程序的基本结构

|-flasky
 |-app/
    |-templates/
    |-static/
    |-main/
        |-__init__.py
        |-errors.py
        |-forms.py
        |-views.py
    |-__init__.py
    |-email.py
    |-models.py
 |-migrations/
 |-tests/
    |-__init__.py
    |-test*.py
 |-venv/
 |-requirements.txt
 |-config.py
 |-manage.py

这种结构有 4 个顶级文件夹:

  • Flask 程序一般都保存在名为 app 的包中;
  • 和之前一样,migrations 文件夹包含数据库迁移脚本;
  • 单元测试编写在 tests 包中;
  • 和之前一样,venv 文件夹包含 Python 虚拟环境

同时还创建了一些新文件:

  • requirements.txt 列出了所有依赖包,便于在其他电脑中重新生成相同的虚拟环境;
  • requirements.txt 列出了所有依赖包,便于在其他电脑中重新生成相同的虚拟环境;
  • manage.py 用于启动程序以及其他的程序任务。
7.2 配置选项

程序经常需要设定多个配置。这方面最好的例子就是开发、测试和生产环境要使用不同的数据库,这样才不会彼此影响。

7.3 程序包

程序包用来保存程序的所有代码、模板和静态文件。我们可以把这个包直接称为app

7.3.1 使用程序工厂函数

在单个文件中开发程序很方便,但却有个很大的缺点,因为程序在全局作用域中创建,所以无法动态修改配置。运行脚本时,程序实例已经创建,再修改配置为时已晚。这一点对单元测试尤其重要,因为有时为了提高测试覆盖度,必须在不同的配置环境中运行程序。

这个问题的解决方法是延迟创建程序实例,把创建过程移到可显式调用的工厂函数中。这种方法不仅可以给脚本留出配置程序的时间,还能够创建多个程序实例,这些实例有时在测试中非常有用。

7.3.2 在蓝本中实现程序功能

蓝本和程序类似,也可以定义路由。不同的
是,在蓝本中定义的路由处于休眠状态,直到蓝本注册到程序上后,路由才真正成为程序的一部分。使用位于全局作用域中的蓝本时,定义路由的方法几乎和单脚本程序一样。

7.4 启动脚本

顶级文件夹中的 manage.py 文件用于启动程序。

7.5 需求文件

程序中必须包含一个 requirements.txt 文件,用于记录所有依赖包及其精确的版本号。如果要在另一台电脑上重新生成虚拟环境,这个文件的重要性就体现出来了,例如部署程序时使用的电脑。pip 可以使用如下命令自动生成这个文件:

(venv) $ pip freeze >requirements.txt
7.6 单元测试
7.7 创建数据库
8.1 Flask的认证扩展
8.2 密码安全性
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容