《Flask入门教程》官网:https://tutorial.helloflask.com/
目录
- 第一章:准备工作
- 第二章:Hello, Flask!
- 第三章:模板
- 第四章:静态文件
- 第五章:数据库
- 第六章:模板优化
- 第七章:表单
- 第八章:用户认证
- 第十章:组织你的代码
- 第十一章:部署上线
第一章:准备工作
使用下面的命令即可为当前项目创建一个虚拟环境:python -m venv env。这会在当前目录创建一个包含 Python 解释器环境的虚拟环境文件夹,名称为 env。
使用下面的命令来激活虚拟环境:env\Scripts\activate。这时命令提示符前会显示虚拟环境的名称,表示已经激活成功。
第二章:Hello, Flask!
Flask 是典型的微框架,作为 Web 框架来说,它仅保留了核心功能:请求响应处理和模板渲染。这两类功能分别由 Werkzeug(WSGI 工具库)和 Jinja(模板渲染库)完成。
在项目根目录执行flask run,Flask将会使用内置的开发服务器运行同目录下的app.py,浏览器输入http://localhost:5000/即可访问。
视图函数(view funciton):
 (1)在Flask 程序app.py中注册。视图函数可以理解为“请求处理函数”。注册的方法是使用 @app.route() 装饰器来为函数绑定对应的 URL。
 (2)一个视图函数也可以绑定多个 URL,这通过附加多个装饰器实现。
 (3)URL中的变量用尖括号对<>包裹,视图函数头中需声明同名变量,在函数体中用字符串引号对中的花括号对访问变量,使用markupsafe.escape(s)进行转义处理,如return f'User: {escape(name)}'(注意不要漏掉f)。
 (4)视图函数的名称可以作为代表某个路由的端点(endpoint),同时用来生成视图函数对应的 URL。Flask 提供了一个 url_for 函数来生成 URL。
管理环境变量:执行pip install python-dotenv。在根目录下创建2个文件:.flaskenv 和 .env。当 python-dotenv 安装后,Flask 会从这2个文件读取环境变量并设置。.flaskenv 用来存储 Flask 命令行系统相关的公开环境变量;而 .env 则用来存储敏感数据,不应该提交进 Git 仓库(添加到.gitignore)。
开启调试模式:在 .flaskenv 文件里,写入一行 FLASK_DEBUG=1。调试模式开启后,当程序出错,浏览器页面上会显示错误信息;代码出现变动后,程序会自动重载(但是页面需要手动刷新)。
第三章:模板
包含变量和运算逻辑的 HTML 或其他格式的文本叫做模板,执行这些变量替换和逻辑计算工作的过程被称为渲染,这个工作由模板渲染引擎Jinja2来完成。
默认情况下,Flask 会从程序同级目录的 templates 文件夹中寻找模板。
模板基本语法:
- {{ ... }}用来标记变量。
- {% ... %}用来标记语句,比如 if 语句,for 语句等。
- {# ... #}用来写注释。
为了方便对变量进行处理,Jinja2 提供了一些过滤器,通过在变量名后附上|过滤器名来使用。
渲染模板:render_template(template_name,context) ,其中template_name为模板文件名(相对于 templates 根目录的文件路径),context为模板内变量(可以有多个)。
进阶:使用 Faker 可以实现自动生成虚拟数据
第四章:静态文件
静态文件(static files)指的是内容不需要动态生成的文件。比如图片、CSS 文件和 JavaScript 脚本等。静态文件保存在与程序同目录的static文件夹中。
在 HTML 文件里,引入这些静态文件需要给出资源所在的 URL。这些文件的 URL 可以通过 Flask 提供的 url_for() 函数来生成。
添加图片:建议把图片放在static/images中。
添加 CSS:可以借助前端框架来完善页面样式,比如 Bootstrap、Semantic-UI、Foundation 等。它们提供了大量的 CSS 定义和动态效果,使用起来非常简单。
第五章:数据库
SQLAlchemy是一个 Python 数据库ORM工具。定义 Python 类来表示数据库里的一张表,通过对这个类进行各种操作来代替写 SQL 语句。这个类称为模型类,类中的属性称为字段。
安装:pip install flask-sqlalchemy==2.5.1 sqlalchemy==1.4.47
初始化:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)  # 传入程序实例 app
设置数据库 URI:app.config['SQLALCHEMY_DATABASE_URI']=...
定义模型类:模型类要声明继承 db.Model。每一个类属性(字段)要实例化 db.Column,传入的参数为字段的类型(Integer, String (size), DateTime, Float)。在 db.Column() 中可以添加额外的选项,比如primary_key=True,nullable=False,unique=True、default=...等。
数据库文件(*.db)不需要提交到 Git 仓库。
向数据库中添加记录:创建模型对象obj,调用db.session.add(obj),然后调用db.session.commit()提交更改。
查询数据库记录:<模型类>.query.<过滤方法(可选)>.<查询方法>。如Movie.query.filter_by(title='Mahjong')或Movie.query.filter(Movie.title=='Mahjong'),这两条查询是等价的。
参照完整性: 可查阅Flask-SQLAlchemy 文档的“声明模型”章节。
第六章:模板优化
对于多个模板内都需要使用的变量,可以使用 app.context_processor 装饰器注册一个模板上下文处理函数。这个函数返回的变量(以字典键值对的形式)将会统一注入到每一个模板的上下文环境中,因此可以直接在模板中使用。
对于模板内容重复的问题,Jinja2 提供了模板继承的支持。父模板一般被称为基模板(base template),基模板中包含完整的 HTML 结构和导航栏、页首、页脚等通用部分。在子模板里使用 extends 标签来声明继承自某个基模板。
基模板中需要在实际的子模板中追加或重写的部分则可以定义成块(block)。块使用 block 标签创建, {% block 块名称 %} 作为开始标记,{% endblock %} 或 {% endblock 块名称 %} 作为结束标记。通过在子模板里定义一个同样名称的块,可以向基模板的对应块位置追加或重写内容。默认的块重写行为是覆盖,如果你想向父块里追加内容,可以在子块中使用 super() 声明,即 {{ super() }}。
【提示】因为基模板会被所有其他页面模板继承,如果你在基模板中使用了某个变量,那么这个变量也需要使用模板上下文处理函数注入到模板里。
第七章:表单
当表单中的提交按钮被按下,请求会默认发往当前 URL,在<form>元素使用 action 属性自定义目标 URL。
视图默认只接受 GET 请求,因此对于POST请求,需要在@app.route中指定methods=['GET', 'POST']。
Flask 会在请求触发后把请求信息放到 request 对象里,只能在视图函数内部调用它。它包含请求相关的所有信息,比如请求的路径(request.path)、请求的方法(request.method)、表单数据(request.form,是一个特殊的字典)、查询字符串(request.args)等等。
flash() 函数用来在视图函数里向模板传递提示消息(把消息存储到session里),get_flashed_messages() 函数则用来在模板中获取提示消息。
Flask 提供的 session 对象用来在请求间存储数据,它会把数据签名后存储到浏览器的 Cookie 中。设置签名所需的密钥:app.config['SECRET_KEY'] = 'dev'(这个密钥的值在开发时可以随便设置。基于安全的考虑,在部署时应该设置为随机字符)
redirect() 函数用于生成重定向响应,传入重定向的目标 URL 作为参数。
为了安全的考虑,一般使用 POST 请求来提交删除请求,也就是使用表单来实现(而不是创建删除链接)。为了让表单中的删除按钮和旁边的按钮排成一行,需要为表单元素添加CSS 定义:.inline-form {display: inline;}。
【提示】 对于复杂的程序,一般会使用集成了 WTForms 的扩展 Flask-WTF 来简化表单处理。通过编写表单类,定义表单字段和验证器,它可以自动生成表单对应的 HTML 代码,并在表单提交时验证表单数据,返回对应的错误消息。更重要的,它还内置了 CSRF(跨站请求伪造) 保护功能。 使用 Flask-WTF 时,表单类在模板中的渲染代码基本相同,可以编写宏来渲染表单字段。如果你使用 Bootstap,那么扩展 Bootstrap-Flask 内置了多个表单相关的宏,可以简化渲染工作。
第八章:用户认证
Flask 的依赖 Werkzeug 内置了用于生成和验证密码散列值的函数,werkzeug.security.generate_password_hash() 用来为给定的密码生成密码散列值,而 werkzeug.security.check_password_hash() 则用来检查给定的散列值和密码是否对应。
使用 Flask-Login 实现用户认证:
 (1)安装:pip install flask-login
 (2)实例化扩展类:login_manager = LoginManager(app)
 (3)实现一个“用户加载回调函数”。该函数的返回值会存储在Flask-Login的current_user 变量中。
 (4)让存储用户的模型类继承 Flask-Login 提供的 UserMixin 类
用户登录使用 Flask-Login 提供的 login_user() 函数实现,需要传入用户模型类对象作为参数。登出操作则需要调用 logout_user() 函数。
认证保护:在 Web 程序中,有些页面或 URL 不允许未登录的用户访问,而页面上有些内容则需要对未登陆的用户隐藏,这就是认证保护。对于不允许未登录用户访问的视图,只需要为视图函数附加一个 @login_required 装饰器就可以将未登录用户拒之门外。添加了这个装饰器后,如果未登录的用户访问对应的 URL,Flask-Login 会把用户重定向到登录页面,并显示一个错误提示。为了让这个重定向操作正确执行,还需要把 login_manager.login_view 的值设为我们程序的登录视图端点(函数名)。
第十章:组织你的代码
创建一个包,然后把 app.py 中的代码按照类别分别放到多个模块里。
| 模块 | 作用 | 
|---|---|
| __init__.py | 包构造文件,创建程序实例 | 
| views.py | 视图函数 | 
| errors.py | 错误处理函数 | 
| models.py | 模型类 | 
| commands.py | 命令函数 | 
包构造文件:存放创建程序实例、初始化扩展的代码。在函数内导入模型类,在文件结尾导入包中的其他模块。
其他文件:使用app变量之前,需要from 包名 import app
【提示】《Flask Web 开发实战》第 8 章介绍了大型项目结构以及如何使用蓝本和工厂函数组织程序。
第十一章:部署上线
生成依赖列表:pip freeze > requirements.txt
把需要在生产环境下使用的配置改为优先从环境变量(.env文件)中读取,如果没有读取到,则使用默认值:
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev')
app.config['SQLALCHEMY_DATABASE_URI'] = prefix + os.path.join(os.path.dirname(app.root_path), os.getenv('DATABASE_FILE', 'data.db'))
在项目根目录创建一个 wsgi.py 脚本,在这个脚本中加载环境变量,并导入程序实例以供部署时使用。