《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
脚本,在这个脚本中加载环境变量,并导入程序实例以供部署时使用。