第一章:Flask 入门与环境搭建
1.1 Flask 简介与特点
| 概念名称 | 说明 | 注意事项 |
|---|
| Flask 简介 | Flask 是一个使用 Python 编写的轻量级 Web 框架,基于 Werkzeug WSGI 工具箱和 Jinja2 模板引擎。 | 本节为理论介绍,不涉及具体方法调用。 |
| 轻量级特性 | Flask 被称为”微框架”(Micro-framework),核心保持简单但可扩展性极强,通过插件机制添加 ORM、表单验证等功能。 | 轻量级不意味着功能弱,而是指框架核心精简,开发者可按需选择扩展。 |
| 核心优势 | 灵活、易上手、社区活跃,适合中小型项目和微服务架构。 | 对比 Django 等全栈框架,Flask 更侧重”自由组合”,开发者需要自行选择组件。 |
1.2 安装 Flask 及依赖管理
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| pip install | pip install flask | 安装 Flask 框架 | pip install flask | 建议在虚拟环境中安装,避免依赖冲突。 |
| pipenv install | pipenv install flask | 使用 Pipenv 管理依赖和虚拟环境 | pipenv install flask | 自动创建 Pipfile,推荐用于项目级依赖管理。 |
| conda install | conda install -c conda-forge flask | 使用 Conda 安装 Flask | conda install -c conda-forge flask | 适用于使用 Anaconda 或 Miniconda 的用户。 |
1.3 第一个 Flask 应用:Hello World
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Flask() | Flask(__name__) | 创建 Flask 应用实例 | app = Flask(__name__) | 必须传入 __name__ 参数以确定应用路径。 |
| app.route() | @app.route('/') | 装饰视图函数并绑定 URL 路由 | @app.route('/')
def hello():
return "Hello, World!" | 路由装饰器必须作用于函数。 |
| app.run() | app.run() | 启动内置开发服务器 | if __name__ == '__main__':
app.run() | 仅用于开发环境,生产环境需使用 WSGI 服务器。 |
完整示例:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello, World!"
if __name__ == '__main__':
app.run()
1.4 运行模式与调试设置(debug、host、port)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| app.run() | app.run(debug=True) | 启用调试模式,自动重启并显示错误信息 | app.run(debug=True) | 生产环境严禁开启 debug=True,存在安全风险。 |
| app.run() | app.run(host='0.0.0.0') | 设置监听主机地址,允许外部访问 | app.run(host='0.0.0.0') | 默认为 127.0.0.1,仅本地可访问。 |
| app.run() | app.run(port=5001) | 指定服务器监听端口 | app.run(port=5001) | 确保端口未被占用,避免冲突。 |
| app.run() | app.run(debug=True, host='0.0.0.0', port=5001) | 组合参数启动服务 | app.run(debug=True, host='0.0.0.0', port=5001) | 开发调试常用配置,便于局域网测试。 |
1.5 项目结构初识
| 概念名称 | 说明 | 注意事项 |
|---|
| 标准 Flask 项目结构 | 推荐的标准目录结构便于维护与扩展。 | 推荐遵循此结构,在实际项目中可以根据需要调整。 |
推荐项目结构:
myapp/
├── app.py
├── templates/
├── static/
│ ├── css/
│ ├── js/
│ └── images/
入口文件写法:
if __name__ == '__main__':
app.run()
注意事项:
if __name__ == '__main__': 用于判断是否直接运行脚本,避免在导入时自动执行 app.run()。
templates/ 目录存放 Jinja2 模板文件,static/ 目录存放 CSS、JS、图片等静态资源。
第二章:路由与视图函数
2.1 基本路由定义(@app.route)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| app.route() | @app.route('/path') | 将 URL 路由绑定到视图函数 | @app.route('/')
def index():
return 'Home Page' | 必须使用装饰器语法,路径以 / 开头。 |
| app.add_url_rule() | app.add_url_rule(rule, endpoint, view_func) | 手动添加路由规则(替代装饰器) | def about():
return 'About'
app.add_url_rule('/about', 'about', about) | 适用于动态注册或避免装饰器的场景。 |
2.2 支持的 HTTP 方法(GET、POST、PUT、DELETE 等)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| app.route() | @app.route('/login', methods=['GET', 'POST']) | 指定视图函数支持的 HTTP 方法 | @app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return 'Logged in'
return '...' | 默认只允许 GET 方法,POST 需显式声明。 |
| methods 参数 | methods=['PUT'] | 限制访问方法类型 | @app.route('/api/user', methods=['PUT'])
def update_user():
return 'Updated' | 提高安全性,防止非法请求方式访问。 |
2.3 动态路由与变量规则(int:id、string:name 等)
| 转换器 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| int | <int:user_id> | 接收整数类型的参数 | @app.route('/user/<int:user_id>')
def user_profile(user_id):
return f'User ID: {user_id}' | 自动转换为 int 类型,非数字会返回 404。 |
| string | <string:name> | 接收字符串类型的参数(默认类型) | @app.route('/hello/<string:name>')
def greet(name):
return f'Hello {name}' | string 是默认类型,可省略不写。 |
| float | <float:amount> | 接收浮点数类型的参数 | @app.route('/price/<float:amount>')
def show_price(amount):
return f'Price: ${amount}' | 不支持科学计数法,必须是有效小数格式。 |
| path | <path:subpath> | 接收包含斜杠的路径片段 | @app.route('/file/<path:filename>')
def read_file(filename):
return f'Reading {filename}' | path 类型可匹配多级路径,如 dir/file.txt。 |
2.4 URL 构建与 url_for 函数
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| url_for() | url_for('endpoint', **values) | 根据端点名生成 URL | @app.route('/home')
def home():
return 'Home'
link = url_for('home') # '/home' | 更安全且便于重构,避免硬编码 URL。 |
| url_for() 带参数 | url_for('profile', user_id=123) | 生成带参数的 URL | url = url_for('profile', user_id=123)
# '/user/123' | 参数名需与路由变量一致。 |
| _external 参数 | url_for('home', _external=True) | 生成完整绝对 URL | url_for('home', _external=True)
# http://localhost:5000/home | 用于邮件链接或 API 回调等外部引用场景。 |
2.5 路由参数选项与自定义转换器
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 自定义转换器类 | 继承 werkzeug.routing.BaseConverter | 定义新的路径匹配逻辑 | 见下方完整示例 | 必须设置 regex 属性用于正则匹配。 |
| 注册转换器 | app.url_map.converters['regex'] = RegexConverter | 注册自定义 URL 转换器 | app.url_map.converters['re'] = RegexConverter | 高级功能,用于复杂路径匹配。 |
| 使用自定义转换器 | <converter:name> | 在路由中使用自定义转换器 | `@app.route(’/<re(“admin | moderator”):role>‘)<br/>def dashboard(role):<br/> return f’{role} panel’` |
自定义转换器完整示例:
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
def __init__(self, url_map, *args):
super().__init__(url_map)
self.regex = args[0]
app.url_map.converters['re'] = RegexConverter
@app.route('/<re("[a-z]+"):value>')
def show(value):
return f'Value: {value}'
第三章:请求与响应处理
3.1 请求对象 request 的常用属性与方法
| 方法/属性 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| request.method | request.method | 获取当前请求的 HTTP 方法 | if request.method == 'POST':
do_something() | 常用于判断请求类型。 |
| request.path | request.path | 获取请求路径(不含查询参数) | path = request.path # 如 '/login' | 不包含域名和查询字符串。 |
| request.url | request.url | 获取完整请求 URL | full_url = request.url # 含协议、主机、路径、查询 | 包含所有信息,可用于日志记录。 |
| request.headers | request.headers.get('Header-Name') | 获取请求头信息 | user_agent = request.headers.get('User-Agent') | 不区分大小写,推荐使用 get() 方法。 |
| request.remote_addr | request.remote_addr | 获取客户端 IP 地址 | ip = request.remote_addr | 反向代理环境下可能需要从 X-Forwarded-For 获取。 |
3.2 获取查询参数、表单数据、JSON 数据
| 方法/属性 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| request.args | request.args.get('key') | 获取 URL 查询参数(GET 参数) | name = request.args.get('name') # ?name=Alice | 返回 ImmutableMultiDict,使用 get() 更安全。 |
| request.form | request.form.get('username') | 获取表单提交的数据 | username = request.form.get('username') | 仅对 POST/PUT 表单有效,Content-Type 需为 application/x-www-form-urlencoded 或 multipart/form-data。 |
| request.get_json() | request.get_json() | 获取 JSON 格式的请求体数据 | data = request.get_json()
if data:
value = data.get('field') | 推荐使用 get_json(),自动解析,若无数据返回 None。 |
| request.values | request.values.get('key') | 合并 args 和 form 的数据 | value = request.values.get('search') | 当不确定参数来源时可用。 |
3.3 文件上传处理
| 方法/属性 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| request.files | request.files['file'] | 获取上传的文件对象 | file = request.files['photo']
if file.filename != '':
file.save('/uploads/photo.jpg') | 必须在 HTML 表单中设置 enctype="multipart/form-data"。 |
| FileStorage.filename | file.filename | 获取上传文件原始名称 | filename = file.filename | 用户可伪造,不可直接用于保存。 |
| FileStorage.save() | file.save('/path/to/save') | 将上传文件保存到服务器 | file.save(os.path.join('/upload', secure_filename(file.filename))) | 必须确保目录存在,建议使用 secure_filename 防止路径穿越。 |
| request.content_length | request.content_length | 获取请求体总长度 | if request.content_length > 16 * 1024 * 1024:
abort(413) # 请求过大 | 可用于限制上传文件大小。 |
3.4 响应对象 Response 的构造方式
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| make_response() | make_response(body, status, headers) | 创建可修改的响应对象 | from flask import make_response
resp = make_response('Hello', 200)
resp.headers['X-Custom'] = 'Value'
return resp | 用于添加自定义头或后期修改响应。 |
| Response() 直接实例化 | Response(response='data', status=200) | 手动创建响应实例 | from werkzeug.wrappers import Response
return Response('Custom', status=201) | 较少直接使用,通常通过 make_response() 封装。 |
| 返回元组 | return 'body', 200, {'Header': 'Value'} | 返回 (响应体, 状态码, 头部) 元组 | return 'Created', 201, {'Location': '/new'} | Flask 自动转换为响应对象,简洁但不够灵活。 |
3.5 返回 JSON、重定向、自定义状态码
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| jsonify() | jsonify(key=value) 或 jsonify(dict) | 返回 JSON 响应,自动设置 Content-Type | from flask import jsonify
return jsonify(message='OK', code=200) | 仅支持字典、列表或基本类型,不支持复杂对象。 |
| redirect() | redirect('/target') 或 redirect(url_for('endpoint')) | 返回重定向响应 | from flask import redirect, url_for
return redirect(url_for('login')) | 推荐结合 url_for 使用,避免硬编码。 |
| abort() | abort(404) | 立即中断并返回指定错误状态码 | from flask import abort
if not user:
abort(404) | 常用于资源未找到或权限不足等情况。 |
| Response 自定义状态码 | make_response('Error', 422) | 自定义状态码返回普通响应 | return make_response('Invalid input', 422) | 用于语义化错误提示,如表单验证失败。 |
第四章:模板渲染(Jinja2)
4.1 使用 render_template 渲染 HTML
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| render_template() | render_template('template.html', **context) | 渲染模板并返回 HTML 响应 | from flask import render_template
@app.route('/')
def index():
return render_template('index.html', title='Home') | 模板文件需放在 templates/ 目录下。 |
| render_template_string() | render_template_string(source, **context) | 直接渲染字符串模板 | source = '<h1>Hello {{ name }}</h1>'
render_template_string(source, name='Alice') | 适用于动态生成的模板内容,注意注入风险。 |
4.2 模板变量与控制结构(if、for)
| 结构 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 变量输出 | {{ variable }} | 输出变量值 | Hello {{ name }} | 自动转义 HTML 特殊字符,防止 XSS。 |
| if 条件判断 | {% if condition %}...{% endif %} | 条件渲染 | {% if user %}
Welcome {{ user.name }}
{% endif %} | 支持 elif、else。 |
| for 循环 | {% for item in list %}...{% endfor %} | 遍历序列 | {% for user in users %}
<li>{{ user.name }}</li>
{% endfor %} | 支持 loop.index、loop.first 等内置变量。 |
4.3 模板继承与布局设计
| 结构 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| extends | {% extends "base.html" %} | 继承父模板 | base.html 中定义通用布局,子模板继承。 | 每个模板最多使用一次 extends。 |
| block | {% block content %}{% endblock %} | 定义可被覆盖的区块 | 在 base.html 中定义 block,在子模板中重写。 | 常见块名:title、content、scripts。 |
| super() | {{ super() }} | 调用父模板中的 block 内容 | {% block styles %}{{ super() }}{% endblock %} | 保留父级样式或脚本的同时扩展内容。 |
模板继承示例:
base.html:
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
index.html:
{% extends "base.html" %}
{% block title %}Home Page{% endblock %}
{% block content %}
<h1>Welcome!</h1>
{% endblock %}
4.4 过滤器与宏的使用
| 结构 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 过滤器 | `{{ variable | filter }}` | 转换变量输出格式 | `{{ name |
| 定义宏 | {% macro input_field(name, value='') %}...{% endmacro %} | 创建可复用的 HTML 片段 | {% macro text_input(name) %}
<input type="text" name="{{ name }}">
{% endmacro %} | 类似函数,提高模板复用性。 |
| 导入宏 | {% from "forms.html" import input_field %} | 在其他模板中使用宏 | {% from "macros.html" import input_field %}
{{ input_field('username') }} | 保持模板整洁,避免重复代码。 |
4.5 安全机制:自动转义与 safe 过滤器
| 结构 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 自动转义 | {{ user_content }} | 默认转义 HTML 字符防止 XSS | 如果 user_content = '<script>alert()</script>',输出为文本而非执行。 | Jinja2 默认开启,保障安全。 |
| safe 过滤器 | `{{ html_content | safe }}` | 标记内容为安全,不进行转义 | `{{ ‘Bold’ |
| escape 过滤器 | `{{ untrusted | escape }}` | 强制转义内容(即使已标记 safe) | `{{ dirty_html |
第五章:应用配置与上下文
5.1 配置对象 app.config 的使用
| 方法/属性 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| app.config | app.config['KEY'] = value | 设置配置项 | app.config['SECRET_KEY'] = 'dev-secret'
app.config['DEBUG'] = True | 键名通常为大写字符串。 |
| app.config.get() | app.config.get('KEY', default) | 安全获取配置值 | db_uri = app.config.get('DATABASE_URL', 'sqlite:///db.sqlite') | 推荐使用 get() 避免 KeyError。 |
5.2 配置文件加载(from_object、from_pyfile 等)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| from_object() | app.config.from_object(ConfigClass) | 从类或模块加载配置 | class Config:
SECRET_KEY = 'xxx'
app.config.from_object(Config) | 支持类、字符串路径(如 'config.ProductionConfig')。 |
| from_pyfile() | app.config.from_pyfile('config.py') | 从 Python 文件加载配置 | app.config.from_pyfile('config.py') | 文件需在项目路径内,避免绝对路径。 |
| from_envvar() | app.config.from_envvar('CONFIG_PATH') | 从环境变量指向的文件加载 | export CONFIG_PATH=/path/to/config.py
app.config.from_envvar('CONFIG_PATH') | 适合生产环境动态配置。 |
5.3 应用上下文(App Context)与请求上下文(Request Context)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| app.app_context() | with app.app_context(): | 手动推送应用上下文 | with app.app_context():
db.init_app(app) | CLI 或后台任务中需要主动创建上下文。 |
| app.test_request_context() | with app.test_request_context(): | 创建测试请求上下文 | with app.test_request_context('/?name=Bob'):
assert request.args['name'] == 'Bob' | 用于单元测试模拟请求。 |
5.4 current_app 与 g 的使用场景
| 方法/属性 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| current_app | from flask import current_app | 获取当前激活的应用实例 | def get_db_config():
return current_app.config['DATABASE'] | 用于编写可复用的扩展或工具函数。 |
| g | from flask import g | 请求周期内存储临时数据 | g.user = user
# 在 before_request 中设置,后续函数可访问 | 每个请求独立,线程安全,请求结束自动清理。 |
5.5 上下文生命周期管理
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| teardown_appcontext() | @app.teardown_appcontext | 注册应用上下文销毁时的回调 | @app.teardown_appcontext
def close_db(error):
if hasattr(g, 'db'):
g.db.close() | 无论是否出错都会执行,适合资源释放。 |
| has_app_context() | has_app_context() | 判断当前是否在应用上下文中 | if not has_app_context():
raise RuntimeError('No app context') | 编写健壮的工具函数时进行上下文检查。 |
第六章:静态文件与错误处理
6.1 静态文件服务(CSS、JS、图片)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| url_for(‘static’, …) | url_for('static', filename='css/style.css') | 生成静态文件 URL | <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> | 静态文件默认存放在 static/ 目录下。 |
| 修改 static_folder | Flask(__name__, static_folder='assets') | 自定义静态文件目录 | app = Flask(__name__, static_folder='public') | 适应不同项目结构需求。 |
6.2 自定义错误页面(404、500 等)
| 概念名称 | 说明 | 注意事项 |
|---|
| 自定义错误页面 | 设计错误页面模板,创建 templates/404.html 和 templates/500.html。 | 页面应友好提示用户,保持品牌一致性。 |
6.3 使用 errorhandler 装饰器
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| @app.errorhandler() | @app.errorhandler(404) | 捕获指定错误并返回自定义响应 | @app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404 | 可捕获异常类(如 HTTPException)或状态码。 |
| @blueprint.errorhandler() | @bp.errorhandler(403) | 蓝图级别的错误处理 | 在蓝图中定义更细粒度的错误响应。 | 优先级高于全局 handler。 |
6.4 异常捕获与日志记录基础
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| app.logger | app.logger.info('message') | 记录日志信息 | app.logger.error(f'Failed to process: {e}') | 支持 debug、info、warning、error、critical 级别。 |
| logging 模块集成 | import logging
app.logger.addHandler(handler) | 自定义日志处理器 | 添加文件处理器或发送到远程日志服务。 | 生产环境建议将日志写入文件或集中管理。 |
第七章:会话与 Cookie 管理
7.1 启用 Session 支持(SECRET_KEY)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| app.config[‘SECRET_KEY’] | app.config['SECRET_KEY'] = 'your-secret-string' | 设置用于加密 session 数据的密钥 | app.config['SECRET_KEY'] = 'a-very-secret-key-123!' | 必须设置,否则 session 无法使用;生产环境应使用强随机字符串并保密。 |
7.2 使用 session 对象存储用户状态
| 方法/属性 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| session | from flask import session | 在服务器端存储用户会话数据(加密后存于 Cookie) | session['user_id'] = 123
if 'user_id' in session:
user_id = session['user_id'] | 数据存储在客户端,不宜存放敏感或大量信息。 |
| session.get() | session.get('key', default) | 安全获取 session 中的值 | user_id = session.get('user_id') | 推荐使用 get() 避免 KeyError。 |
| session.pop() | session.pop('key', None) | 删除指定 session 键值 | session.pop('user_id', None) | 常用于登出时清除用户信息。 |
| session.clear() | session.clear() | 清除所有 session 数据 | session.clear() | 彻底注销用户会话。 |
7.3 Cookie 的设置与读取(make_response + set_cookie)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| set_cookie() | response.set_cookie(key, value, max_age, ...) | 设置响应中的 Cookie | from flask import make_response
resp = make_response('Set cookie')
resp.set_cookie('theme', 'dark', max_age=60*60*24) | 必须通过 Response 对象设置。 |
| request.cookies.get() | request.cookies.get('cookie_name') | 读取请求中的 Cookie | theme = request.cookies.get('theme', 'light') | 所有 Cookie 都可通过此方式访问。 |
| make_response() | make_response(template_or_string) | 创建可修改的响应对象以设置 Cookie | resp = make_response(render_template('index.html'))
resp.set_cookie('visited', 'yes') | 是设置 Cookie 的前提。 |
7.4 安全设置:HttpOnly、Secure、SameSite
| 参数 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| httponly | set_cookie(..., httponly=True) | 防止 JavaScript 访问 Cookie,抵御 XSS | resp.set_cookie('session_id', 'abc', httponly=True) | 强烈建议对 session cookie 启用。 |
| secure | set_cookie(..., secure=True) | 仅通过 HTTPS 传输 Cookie | resp.set_cookie('session', 'xxx', secure=True) | 生产环境必须启用,避免明文传输。 |
| samesite | set_cookie(..., samesite='Lax') | 防止 CSRF 攻击,控制跨站请求携带 Cookie | resp.set_cookie('auth', 'token', samesite='Strict') | 可选值:'Lax'、'Strict'、'None';'None' 要求 secure=True。 |
第八章:蓝本(Blueprints)与模块化
8.1 蓝图的概念与作用
| 概念名称 | 说明 | 注意事项 |
|---|
| 蓝图(Blueprint) | 模块化组织路由、静态文件和错误处理器,将用户管理、博客、API 等功能拆分为独立蓝图。 | 提高代码可维护性,避免 app.py 过于臃肿。 |
8.2 创建与注册蓝图
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Blueprint() | Blueprint('name', __name__, url_prefix='/path') | 创建蓝图实例 | from flask import Blueprint
admin_bp = Blueprint('admin', __name__, url_prefix='/admin') | 第一个参数为蓝图名,需唯一。 |
| app.register_blueprint() | app.register_blueprint(blueprint) | 将蓝图注册到应用 | app.register_blueprint(admin_bp) | 注册后蓝图中的路由才生效。 |
| url_prefix 参数 | Blueprint(..., url_prefix='/api') | 为蓝图所有路由添加前缀 | 见上例。 | 常用于版本化 API(如 /api/v1)。 |
8.3 蓝图中的路由与静态文件
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| @bp.route() | @admin_bp.route('/dashboard') | 在蓝图中定义路由 | @admin_bp.route('/dashboard')
def dashboard():
return 'Admin Panel' | 路由路径相对于蓝图的 url_prefix。 |
| static_folder 参数 | Blueprint(..., static_folder='static') | 为蓝图指定静态文件目录 | user_bp = Blueprint('users', __name__, static_folder='user_static') | 访问路径为 /blueprint_name/static/file。 |
| static_url_path 参数 | Blueprint(..., static_url_path='/assets') | 自定义静态文件 URL 路径 | 使 /users/assets/style.css 指向本地 user_static/ 目录。 | 灵活控制 URL 结构。 |
8.4 多蓝图应用结构设计
| 概念名称 | 说明 | 注意事项 |
|---|
| 项目结构 | 清晰的功能模块划分。 | 按功能拆分,便于团队协作。 |
推荐多蓝图项目结构:
myapp/
├── main/
│ └── main_bp.py
├── auth/
│ └── auth_bp.py
└── app.py
| 概念名称 | 说明 | 注意事项 |
|---|
| 共享模板与静态文件 | 放置在主 templates/ 和 static/ 目录,多蓝图共用布局和资源。 | 所有蓝图均可使用 base.html,保持 UI 一致性。 |
| 蓝图间通信 | 通过 url_for('blueprint.endpoint') 生成其他蓝图的 URL。 | 必须包含蓝图名作为前缀,如 url_for('auth.login')。 |
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| pip install | pip install Flask-WTF | 安装 Flask-WTF 扩展 | pip install Flask-WTF | 自动安装 WTForms 依赖。 |
| CSRF 保护 | app.config['SECRET_KEY'] | 启用跨站请求伪造保护 | 必须设置 SECRET_KEY。 | Flask-WTF 默认启用 CSRF 防护。 |
9.2 定义表单类与字段验证
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Form 继承 | class MyForm(Form): | 定义表单类 | from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
class NameForm(FlaskForm):
name = StringField('Name')
submit = SubmitField('Submit') | 推荐继承 FlaskForm。 |
| 字段类型 | StringField(), PasswordField() 等 | 创建不同类型的输入字段 | password = PasswordField('Password') | 自动生成对应 HTML 输入类型。 |
| 验证器 | DataRequired(), Email() 等 | 添加字段验证规则 | from wtforms.validators import DataRequired, Email
email = StringField('Email', validators=[DataRequired(), Email()]) | 提交时自动验证,错误存于 form.errors。 |
9.3 在视图中使用表单
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| form.validate_on_submit() | if form.validate_on_submit(): | 判断是否为有效表单提交 | if form.validate_on_submit():
name = form.name.data
# 处理数据 | 封装了 method 判断和验证逻辑。 |
| form.errors | form.errors | 获取验证错误信息 | if not form.validate():
print(form.errors) | 调试或自定义错误处理时使用。 |
9.4 模板中渲染表单
| 方法/语法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| {{ form.hidden_tag() }} | {{ form.hidden_tag() }} | 渲染 CSRF 隐藏字段 | 在表单内第一行使用。 | 必须包含以启用 CSRF 保护。 |
| {{ form.field() }} | {{ form.username() }} | 渲染表单字段 | {{ form.username(class="form-control") }} | 可传递 HTML 属性。 |
| {{ form.field.label }} | {{ form.username.label }} | 渲染字段标签 | {{ form.username.label(class="form-label") }} | 支持自定义文本和属性。 |
9.5 自定义验证器与错误处理
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 自定义函数验证器 | def validate_field(form, field): | 编写复杂验证逻辑 | def validate_username(form, field):
if User.query.filter_by(username=field.data).first():
raise ValidationError('Username taken.') | 抛出 ValidationError 显示错误。 |
| form.validate() | form.validate() | 手动触发验证(不检查方法) | if request.method == 'POST' and form.validate(): | 用于非标准提交场景。 |
第十章:数据库集成(Flask-SQLAlchemy)
10.1 ORM 与 Flask-SQLAlchemy 简介
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| SQLAlchemy() | db = SQLAlchemy(app) 或 db.init_app(app) | 初始化数据库扩展 | from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() | 推荐延迟初始化以支持工厂模式。 |
10.2 模型定义与字段类型
| 字段类型 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| db.Column | db.Column(db.String(80)) | 定义模型字段 | class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False) | 必须指定类型和选项。 |
| 常用类型 | db.Integer, db.String(), db.Text, db.Boolean, db.DateTime | 映射数据库数据类型 | created = db.Column(db.DateTime, default=datetime.utcnow) | 注意时区处理。 |
| primary_key | primary_key=True | 设置主键 | id = db.Column(db.Integer, primary_key=True) | 通常自动递增。 |
10.3 数据库 CRUD 操作
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| db.session.add() | db.session.add(instance) | 添加新记录 | user = User(name='Alice')
db.session.add(user) | 仅加入会话,未提交。 |
| db.session.commit() | db.session.commit() | 提交事务,保存更改 | db.session.commit() | 必须调用才能持久化,可能抛出异常。 |
| db.session.delete() | db.session.delete(instance) | 删除记录 | db.session.delete(user)
db.session.commit() | 实例必须来自数据库查询。 |
| 字段更新 | obj.field = new_value | 修改字段值(需手动 commit) | user.name = 'Bob'
db.session.commit() | 单个对象修改后需提交。 |
10.4 查询 API 与过滤方法
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Model.query | User.query.all() | 获取模型查询入口 | users = User.query.filter_by(active=True).all() | 返回查询对象,可链式调用。 |
| filter_by() | query.filter_by(name='Alice') | 精确匹配字段 | User.query.filter_by(name='Alice').first() | 适用于简单等值查询。 |
| filter() | query.filter(User.name == 'Alice') | 使用表达式过滤 | User.query.filter(User.age > 18).all() | 支持复杂条件和运算符。 |
| first(), all() | query.first(), query.all() | 执行查询并返回结果 | user = User.query.get(1) # 主键查询 | first() 返回第一个或 None,all() 返回列表。 |
10.5 关联关系(一对多、多对多)
| 关系类型 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| db.relationship() | posts = db.relationship('Post', backref='author') | 定义模型间关系 | class User(db.Model):
posts = db.relationship('Post', backref='author') | 用于导航关联对象。 |
| db.ForeignKey() | db.Column(db.Integer, db.ForeignKey('user.id')) | 外键约束 | class Post(db.Model):
author_id = db.Column(db.Integer, db.ForeignKey('user.id')) | 实现一对多关系。 |
| 多对多关系 | 使用辅助表 | 建立多对多连接 | tags_posts = db.Table('tags_posts',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')),
db.Column('post_id', db.Integer, db.ForeignKey('post.id'))) | 通过 db.Table 定义关联表。 |
第十一章:用户认证与授权
11.1 用户登录会话管理
| 概念名称 | 说明 | 注意事项 |
|---|
| 会话管理 | 使用 session 存储用户登录状态。 | 基础认证方式,需配合密码验证。 |
session['user_id'] = user.id
11.2 使用 Flask-Login 实现认证
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| LoginManager() | login_manager = LoginManager() | 初始化登录管理器 | login_manager.init_app(app) | 管理用户会话状态。 |
| @login_manager.user_loader | @login_manager.user_loader | 定义用户加载回调 | @login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id)) | 必须实现,用于从 session 恢复用户。 |
11.3 装饰器 @login_required
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| @login_required | @login_required | 保护视图,仅登录用户可访问 | from flask_login import login_required
@app.route('/profile')
@login_required
def profile():
return 'Your Profile' | 未登录用户将被重定向到登录页。 |
11.4 密码哈希(Werkzeug)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| generate_password_hash() | generate_password_hash(password) | 生成密码哈希 | from werkzeug.security import generate_password_hash
hash = generate_password_hash('password') | 永远不要明文存储密码。 |
| check_password_hash() | check_password_hash(hash, password) | 验证密码是否匹配 | if check_password_hash(user.password, form.password.data):
login_user(user) | 用于用户登录验证。 |
11.5 用户权限控制基础
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 自定义装饰器 | def admin_required(f): | 实现角色或权限检查 | 见下方完整示例。 | 可结合 Flask-Login 的 UserMixin 扩展。 |
自定义权限装饰器示例:
from functools import wraps
from flask import abort
from flask_login import current_user
def admin_required(f):
@wraps(f)
def decorated(*args, **kwargs):
if not current_user.is_admin:
abort(403)
return f(*args, **kwargs)
return decorated
第十二章:API 开发与 RESTful 设计
12.1 RESTful 原则简介
| 概念名称 | 说明 | 注意事项 |
|---|
| RESTful 原则 | 设计基于资源的 URL,使用标准 HTTP 方法。 | 使用名词复数,避免动词。 |
推荐 URL 设计:
GET /users # 获取用户列表
POST /users # 创建用户
GET /users/1 # 获取单个用户
PUT /users/1 # 更新用户
DELETE /users/1 # 删除用户
12.2 使用 Flask 构建 REST API
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| jsonify() | jsonify(data) | 返回 JSON 响应 | return jsonify({'message': 'OK'}) | 自动设置 Content-Type: application/json。 |
| request.get_json() | request.get_json() | 解析 JSON 请求体 | data = request.get_json() | 确保 Content-Type 为 application/json。 |
12.3 请求验证与响应格式统一
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 自定义验证函数 | def validate_data(data): | 验证请求数据结构 | if 'name' not in data:
return jsonify({'error': 'Name required'}), 400 | 统一错误格式便于前端处理。 |
| 包装响应 | def api_response(data, code=200) | 封装标准响应格式 | return jsonify({'success': True, 'data': data}), code | 提高 API 一致性。 |
12.4 使用 Flask-RESTful 扩展(可选)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Api() | api = Api(app) | 初始化 RESTful API 管理器 | from flask_restful import Api, Resource
api = Api(app) | 提供更简洁的类视图 API 定义。 |
| Resource | class UserAPI(Resource): | 定义资源类 | class UserAPI(Resource):
def get(self, id):
return {'id': id}
api.add_resource(UserAPI, '/user/<int:id>') | 按 HTTP 方法定义处理函数。 |
12.5 API 文档生成(Swagger / OpenAPI)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Flask-Swagger 或 apispec | from apispec import APISpec | 生成 OpenAPI 规范 | 结合 Flask-RESTful 自动生成文档。 | 可配合 Swagger UI 展示交互式文档。 |
| 注释或装饰器 | 使用 docstrings 或 @doc 装饰器 | 描述 API 接口 | 在 Resource 类中添加详细说明。 | 提高 API 可用性。 |
第十三章:部署与性能优化
13.1 生产环境部署(Gunicorn、uWSGI)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Gunicorn | gunicorn -w 4 app:app | WSGI HTTP 服务器,生产环境推荐使用。 | pip install gunicorn | 简单易用,适合大多数场景。 |
| uWSGI | uwsgi --http :5000 --wsgi-file app.py --callable app | 高性能应用服务器。 | 支持更多配置选项,性能更强。 | 配置较复杂,适合高负载场景。 |
13.2 使用 Nginx 反向代理
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Nginx 配置 | server { location / { proxy_pass http://127.0.0.1:8000; } } | 转发请求到后端 Flask 应用。 | 处理静态文件、负载均衡、SSL 终止。 | 提高安全性和性能。 |
13.3 静态资源处理优化
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Nginx 服务静态文件 | location /static { alias /path/to/static; } | 由 Nginx 直接返回静态资源。 | 减轻 Flask 应用负担,提升响应速度。 | 生产环境必须配置。 |
| CDN | 使用第三方 CDN 服务 | 加速全球用户访问。 | 将 static/ 目录托管到 CDN。 | 适用于大型应用或全球用户。 |
13.4 日志配置与错误监控
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| logging 配置 | app.logger.addHandler(handler) | 将日志写入文件或发送到服务。 | 配置 RotatingFileHandler 按大小轮转日志。 | 生产环境避免仅输出到控制台。 |
| Sentry | sentry_sdk.init(dsn="...") | 集成错误监控服务。 | 实时捕获并报告异常,便于调试。 | 推荐用于生产环境。 |
13.5 性能测试与调试工具
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Flask-DebugToolbar | DebugToolbarExtension(app) | 开发时调试工具条。 | 显示 SQL 查询、HTTP 请求、配置等信息。 | 仅用于开发,禁止生产环境启用。 |
| pytest-benchmark | @pytest.mark.benchmark | 性能基准测试。 | 测量关键函数执行时间。 | 识别性能瓶颈。 |
第十四章:常用扩展与高级特性
14.1 Flask-WTF(安全表单)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| FlaskForm | class MyForm(FlaskForm): | 安全表单基类,自动集成 CSRF 保护。 | 继承自 WTForms.Form。 | 替代原始 Form 类。 |
| CSRFProtect | CSRFProtect(app) | 全局启用 CSRF 保护。 | 适用于非表单的 AJAX 请求。 | 增强应用安全性。 |
14.2 Flask-Mail(邮件发送)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Mail() | mail = Mail(app) | 初始化邮件扩展。 | 配置 SMTP 服务器参数。 | 用于发送注册确认、密码重置等邮件。 |
| Message() | msg = Message('Subject', recipients=['to@example.com']) | 创建邮件对象。 | msg.body = 'Hello'
mail.send(msg) | 支持 HTML 邮件和附件。 |
14.3 Flask-Caching(缓存机制)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| Cache() | cache = Cache(app, config={'CACHE_TYPE': 'simple'}) | 初始化缓存。 | 支持内存、Redis、Memcached 等后端。 | 减少数据库查询,提升性能。 |
| @cache.cached() | @cache.cached(timeout=60) | 缓存视图输出。 | @cache.cached(timeout=300)
def expensive_view():
return render_template(...) | 适用于计算或查询密集型视图。 |
14.4 Flask-SocketIO(实时通信)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| SocketIO() | socketio = SocketIO(app) | 初始化 WebSocket 支持。 | 支持实时聊天、通知等功能。 | 需使用 gevent 或 eventlet 服务器。 |
| @socketio.on(‘event’) | @socketio.on('message') | 监听客户端事件。 | def handle_message(data):
emit('response', 'Received!') | 实现双向通信。 |
14.5 自定义中间件与钩子函数
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| @app.before_request | @app.before_request | 在每个请求处理前执行,常用于权限检查、请求预处理。 | @app.before_request
def require_login():
if 'user_id' not in session:
return redirect(url_for('login')) | 若返回响应对象或字符串,将终止后续视图执行,直接返回该响应。 |
| @app.after_request | @app.after_request | 在请求处理后、响应发送前执行,用于修改响应头等。 | @app.after_request
def add_header(response):
response.headers['X-Content-Type-Options'] = 'nosniff'
return response | 必须接收并返回 response 对象,不可省略 return。 |
| @app.teardown_request | @app.teardown_request | 请求结束后执行,无论成功或异常,用于资源清理。 | @app.teardown_request
def close_db(error):
if hasattr(g, 'db_conn'):
g.db_conn.close() | 不应依赖返回值,主要用于清理操作;可能在上下文已销毁时调用。 |
| 使用 Werkzeug 中间件 | app.wsgi_app = Middleware(app.wsgi_app) | 封装 WSGI 应用,实现全局中间件(如日志、性能监控)。 | from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1) | 适用于需要在 Flask 处理前/后拦截所有请求的场景,如反向代理适配。 |
注意: @app.before_first_request 在新版本 Flask(2.3+)中已弃用,建议改用应用工厂模式结合 app.app_context() 手动初始化。