1. Flask 基础认知
Flask是由Armin Ronacher开发的轻量级Python Web框架,基于Werkzeug(WSGI工具集)和Jinja2(模板引擎)构建,被称为"微框架(Microframework)"------并非功能薄弱,而是核心极简,可通过扩展灵活扩展功能,对比Django(大而全的框架),Flask更适合小型项目、快速原型开发或需要高度定制化的场景。
核心特点:
- 轻量灵活:核心仅包含路由、请求/响应处理、模板渲染,其余功能通过扩展实现;
- 易学易用:API设计简洁,新手可快速上手;
- 兼容性好:支持Python 3.6+,兼容主流WSGI服务器;
- 丰富的扩展生态:Flask-SQLAlchemy(数据库)、Flask-WTF(表单)、Flask-Login(用户认证)等。
环境搭建 :
首先推荐使用虚拟环境隔离依赖(避免全局环境污染):
bash
# 创建虚拟环境(Python 3.6+)
python -m venv flask_env
# 激活虚拟环境(Windows)
flask_env\Scripts\activate
# 激活虚拟环境(Linux/Mac)
source flask_env/bin/activate
# 安装Flask
pip install flask
# 验证安装
python -c "import flask; print(flask.__version__)"
2. 最小应用:Flask 核心骨架
Flask的最小应用仅需几行代码即可运行,是理解其核心流程的起点:
python
# app.py
from flask import Flask
# 初始化Flask应用:__name__表示当前模块名,Flask以此定位静态文件/模板路径
app = Flask(__name__)
# 路由:将URL路径(/)与视图函数绑定
@app.route('/')
def index():
# 视图函数:处理请求并返回响应
return 'Hello, Flask!'
# 仅在直接运行该脚本时启动开发服务器
if __name__ == '__main__':
# debug=True:开启调试模式(代码修改自动重启、报错显示详细信息)
app.run(debug=True, host='0.0.0.0', port=5000)
运行脚本后,访问http://localhost:5000即可看到"Hello, Flask!",核心要素:
Flask(__name__):创建应用实例,__name__是Flask的"应用根目录"标识;@app.route('/'):路由装饰器,映射URL与视图函数;app.run():启动开发服务器(仅用于开发环境,生产环境需用Gunicorn/Nginx)。
3. 路由系统:URL与视图的映射
视图函数(View Function)是 Flask 中绑定到特定 URL 路由的 Python 函数,也是处理 HTTP 请求的核心载体
路由是Flask的核心之一,负责将用户请求的URL匹配到对应的视图函数,支持多种高级特性:
(1)基本路由与动态路由
python
# 基本路由:固定URL
@app.route('/about')
def about():
return '关于我们'
# 动态路由:URL参数(<string:name> 表示接收字符串类型的name参数)
@app.route('/user/<string:name>') # 类型可省略,默认string;支持int/float/path(含/的字符串)
def user(name):
return f'Hello, {name}!'
# 多URL绑定到同一个视图函数
@app.route('/hi')
@app.route('/hello')
def greet():
return 'Hi there!'
(2)请求方法限定
默认路由仅支持GET请求,可通过methods参数指定支持的HTTP方法(GET/POST/PUT/DELETE等):
python
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 处理POST请求(表单提交)
return '处理登录逻辑'
else:
# 处理GET请求(返回登录页面)
return '返回登录表单'
(3)路由规则进阶
strict_slashes:控制URL末尾的/是否严格匹配(默认True,/about/与/about视为不同);redirect_to:路由重定向;
python
@app.route('/old-path', strict_slashes=False, redirect_to='/new-path')
def old_path():
pass
@app.route('/new-path')
def new_path():
return '新路径'
4. 请求与响应处理
Flask通过request对象封装客户端请求数据,通过返回值/make_response构建响应。
(1)请求对象(request)
需先导入from flask import request,核心属性:
| 属性/方法 | 说明 | 示例 |
|---|---|---|
request.method |
请求方法(GET/POST等) | if request.method == 'POST' |
request.args |
GET参数(URL中的?参数) | request.args.get('page', 1) |
request.form |
POST表单数据 | request.form.get('username') |
request.files |
上传的文件 | request.files['avatar'] |
request.cookies |
请求中的Cookie | request.cookies.get('token') |
request.headers |
请求头信息 | request.headers.get('User-Agent') |
访问http://localhost:5000/user?id=100\&page=2 → 返回 "获取到的 GET 参数:用户 ID=100,页码 = 2"。
URL 中的?是路径和 GET 参数的分隔符,& 是多个 GET 参数之间的分隔符
示例:处理GET/POST请求
python
from flask import Flask, request
app = Flask(__name__)
@app.route('/data', methods=['GET', 'POST'])
def handle_data():
if request.method == 'GET':
# 获取GET参数:?name=张三&age=20
name = request.args.get('name', '匿名') # 第二个参数是默认值
age = request.args.get('age', 0, type=int)
return f'GET请求:姓名{name},年龄{age}'
else:
# 获取POST表单数据
username = request.form['username'] # 无默认值,不存在则抛异常
password = request.form.get('password')
return f'POST请求:用户名{username}'
if __name__ == '__main__':
app.run(debug=True)
(2)响应处理
Flask支持多种响应类型,核心方式:
- 直接返回字符串:自动封装为
Response对象(默认状态码200,Content-Type: text/html); - 返回元组:(响应内容, 状态码, 响应头);
- 使用
make_response构建自定义响应; - 返回JSON:使用
jsonify(自动设置Content-Type: application/json)。
示例:
python
from flask import Flask, make_response, jsonify
app = Flask(__name__)
@app.route('/response1')
def response1():
# 返回元组:内容、状态码、响应头
return '自定义状态码', 404, {'X-Custom-Header': 'Flask'}
@app.route('/response2')
def response2():
# 手动构建Response对象
resp = make_response('自定义响应')
resp.status_code = 201
resp.set_cookie('token', '123456') # 设置Cookie
resp.headers['Content-Type'] = 'text/plain'
return resp
@app.route('/json')
def return_json():
# 返回JSON数据(推荐用jsonify,而非json.dumps)
data = {'name': '张三', 'age': 20}
return jsonify(data) # 等价于 return make_response(json.dumps(data), 200, {'Content-Type': 'application/json'})
if __name__ == '__main__':
app.run(debug=True)
(3)重定向与错误处理
- 重定向:使用
redirect,配合url_for(反向生成URL,避免硬编码); - 错误处理:使用
@app.errorhandler(状态码)装饰器自定义错误页面。
python
from flask import Flask, redirect, url_for, abort
app = Flask(__name__)
@app.route('/index')
def index():
return '首页'
@app.route('/go-index')
def go_index():
# url_for('index'):根据视图函数名生成URL(/index)
return redirect(url_for('index'))
@app.route('/error')
def error():
# 主动抛出404异常
abort(404)
# 自定义404错误页面
@app.errorhandler(404)
def page_not_found(e):
# e是异常对象,包含错误信息
return '页面不存在', 404
# 自定义500错误页面
@app.errorhandler(500)
def server_error(e):
return '服务器内部错误', 500
if __name__ == '__main__':
app.run(debug=True)
5. 模板引擎:Jinja2
Flask内置Jinja2模板引擎,用于将Python变量渲染到HTML中,实现"前后端分离(简易版)",模板文件默认放在项目根目录的templates文件夹下。
(1)基本使用
项目结构:
project/
├── app.py
└── templates/
└── index.html
python
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
# 渲染模板:传递变量name/age到模板
return render_template('index.html', name='张三', age=20)
if __name__ == '__main__':
app.run(debug=True)
templates/index.html:
html
<!DOCTYPE html>
<html>
<head>
<title>Flask模板</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1> {# 变量渲染 #}
<p>年龄:{{ age + 1 }}</p> {# 支持简单表达式 #}
</body>
</html>
(2)Jinja2核心语法
- 变量:
{``{ 变量名 }},支持字典({``{ user.name }}/{``{ user['name'] }})、列表({``{ list[0] }}); - 控制结构:
{% if/for %},需闭合{% endif/endfor %};
html
{# 条件判断 #}
{% if age >= 18 %}
<p>成年</p>
{% else %}
<p>未成年</p>
{% endif %}
{# 循环 #}
<ul>
{% for item in ['苹果', '香蕉', '橙子'] %}
<li>{{ loop.index }}: {{ item }}</li> {# loop.index是循环索引(从1开始) #}
{% endfor %}
</ul>
-
模板继承:通过
{% extends %}/{% block %}实现模板复用(核心减少重复代码);
基模板(templates/base.html):html<!DOCTYPE html> <html> <head> <title>{% block title %}默认标题{% endblock %}</title> </head> <body> <div class="header">头部</div> <div class="content"> {% block content %}{% endblock %} {# 子模板填充的内容 #} </div> <div class="footer">底部</div> </body> </html>子模板(templates/home.html):
html{% extends 'base.html' %} {# 继承基模板 #} {% block title %}首页{% endblock %} {# 重写title块 #} {% block content %} <h1>首页内容</h1> {% endblock %} -
宏(Macro):类似函数,封装可复用的HTML片段;
html
{% macro input(name, type='text', value='') %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}
{# 使用宏 #}
{{ input('username') }}
{{ input('password', type='password') }}
- 过滤器:修改变量显示格式,
{``{ 变量|过滤器 }},常用:safe(禁用转义)、length(长度)、upper(大写);
html
{{ '<h1>测试</h1>'|safe }} {# 渲染为<h1>测试</h1>,而非转义后的字符串 #}
{{ ['a','b']|length }} {# 输出2 #}
{{ 'hello'|upper }} {# 输出HELLO #}
6. 会话与状态管理
HTTP是无状态协议,Flask通过Cookie和Session实现状态保持:
(1)Cookie
Cookie是存储在客户端浏览器的小型文本文件,Flask通过set_cookie/request.cookies操作:
python
from flask import Flask, make_response, request
app = Flask(__name__)
@app.route('/set-cookie')
def set_cookie():
resp = make_response('设置Cookie')
# 设置Cookie:key=value,max_age是过期时间(秒)
resp.set_cookie('username', '张三', max_age=3600)
return resp
@app.route('/get-cookie')
def get_cookie():
# 获取Cookie
username = request.cookies.get('username', '匿名')
return f'Cookie中的用户名:{username}'
if __name__ == '__main__':
app.run(debug=True)
(2)Session
Session是"服务器端的Cookie":将敏感数据存储在服务器,仅将加密的session_id存储在客户端Cookie中,使用前需设置密钥(SECRET_KEY)用于加密:
python
from flask import Flask, session
app = Flask(__name__)
# 必须设置密钥(开发时可随便写,生产环境需用随机强密钥)
app.secret_key = 'your-secret-key-123456' # 生产环境建议从环境变量读取
@app.route('/set-session')
def set_session():
# 存储数据到Session
session['username'] = '张三'
session['age'] = 20
return 'Session已设置'
@app.route('/get-session')
def get_session():
# 获取Session数据
username = session.get('username', '匿名')
age = session.get('age', 0)
return f'Session:用户名{username},年龄{age}'
@app.route('/clear-session')
def clear_session():
# 删除单个Session键
session.pop('age', None)
# 清空所有Session
# session.clear()
return 'Session已清理'
if __name__ == '__main__':
app.run(debug=True)
7. 蓝图(Blueprint):模块化开发
当项目规模扩大时,单一app.py会变得臃肿,蓝图(Blueprint)可将功能拆分为独立模块(如用户模块、商品模块),实现代码解耦。
示例:拆分用户模块和商品模块
项目结构:
project/
├── app.py
├── users/
│ ├── __init__.py
│ └── views.py # 用户模块视图
└── goods/
├── __init__.py
└── views.py # 商品模块视图
users/views.py:
python
from flask import Blueprint
# 创建蓝图:第一个参数是蓝图名,第二个是模块名,url_prefix是该蓝图所有路由的前缀
user_bp = Blueprint('user', __name__, url_prefix='/user')
# 蓝图的路由(最终URL:/user/login)
@user_bp.route('/login')
def login():
return '用户登录'
@user_bp.route('/profile')
def profile():
return '用户个人中心'
goods/views.py:
python
from flask import Blueprint
goods_bp = Blueprint('goods', __name__, url_prefix='/goods')
@goods_bp.route('/list')
def goods_list():
return '商品列表'
@goods_bp.route('/detail/<int:id>')
def goods_detail(id):
return f'商品详情:{id}'
app.py(注册蓝图):
python
from flask import Flask
from users.views import user_bp
from goods.views import goods_bp
app = Flask(__name__)
# 注册蓝图到应用
app.register_blueprint(user_bp)
app.register_blueprint(goods_bp)
if __name__ == '__main__':
app.run(debug=True)
访问http://localhost:5000/user/login(用户登录)、http://localhost:5000/goods/list(商品列表)即可验证,蓝图支持独立的模板/静态文件路径、错误处理等,是Flask模块化开发的核心。
8. 配置管理
Flask支持多种配置方式,核心是app.config(字典对象),推荐按环境(开发/测试/生产)分离配置:
(1)基本配置方式
python
from flask import Flask
app = Flask(__name__)
# 方式1:直接设置
app.config['SECRET_KEY'] = '123456'
app.config['DEBUG'] = True
# 方式2:从字典加载
config = {
'SECRET_KEY': '123456',
'DEBUG': True
}
app.config.update(config)
# 方式3:从配置类加载(推荐,便于环境分离)
class DevelopmentConfig:
DEBUG = True
SECRET_KEY = 'dev-secret-key'
class ProductionConfig:
DEBUG = False
SECRET_KEY = 'prod-secret-key' # 生产环境用随机生成的密钥
# 加载配置类
app.config.from_object(DevelopmentConfig)
# 方式4:从环境变量加载(生产环境推荐,避免硬编码敏感信息)
# app.config.from_envvar('FLASK_CONFIG_FILE') # 读取环境变量指向的配置文件
9. 钩子函数(中间件)
Flask提供多个钩子函数,用于在请求处理的不同阶段执行自定义逻辑:
| 钩子函数 | 执行时机 |
|---|---|
before_request |
每个请求处理前执行 |
after_request |
每个请求处理后执行(无异常) |
teardown_request |
每个请求处理后执行(无论是否异常) |
before_first_request |
第一个请求处理前执行(Flask 2.0+已废弃,改用app.before_first_request_funcs) |
示例:
python
from flask import Flask, request
app = Flask(__name__)
# 请求处理前:记录请求信息
@app.before_request
def log_request():
print(f'请求路径:{request.path},方法:{request.method}')
# 请求处理后:添加响应头
@app.after_request
def add_header(resp):
resp.headers['X-Processed-By'] = 'Flask'
return resp
# 请求处理完成后(无论是否异常):清理资源
@app.teardown_request
def teardown(exception):
if exception:
print(f'请求异常:{exception}')
print('请求处理完成,清理资源')
@app.route('/')
def index():
return 'Hello, Flask!'
if __name__ == '__main__':
app.run(debug=True)
10. 常用扩展
Flask的核心功能有限,扩展是其生态的核心,以下是最常用的扩展:
-
Flask-SQLAlchemy :ORM框架,简化数据库操作(支持MySQL/PostgreSQL/SQLite等);
安装:pip install flask-sqlalchemy
示例:pythonfrom flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) # 配置数据库连接(SQLite示例,文件型数据库) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 关闭修改跟踪(提升性能) db = SQLAlchemy(app) # 定义模型(对应数据库表) class User(db.Model): id = db.Column(db.Integer, primary_key=True) # 主键 username = db.Column(db.String(80), unique=True, nullable=False) # 唯一、非空 email = db.Column(db.String(120), unique=True, nullable=False) def __repr__(self): return f'<User {self.username}>' # 创建表(需在Python交互环境执行) # with app.app_context(): # db.create_all() @app.route('/add-user') def add_user(): # 添加数据 user = User(username='张三', email='zhangsan@example.com') db.session.add(user) db.session.commit() return '用户添加成功' @app.route('/users') def get_users(): # 查询数据 users = User.query.all() return f'所有用户:{users}' if __name__ == '__main__': app.run(debug=True) -
Flask-WTF:封装WTForms,简化表单验证;
-
Flask-Login:处理用户登录、登出、会话管理;
-
Flask-Migrate:基于Alembic,实现数据库迁移(表结构修改);
-
Flask-CORS:解决跨域问题(前后端分离项目必备)。
11. 生产环境部署
开发环境的app.run()仅用于调试,生产环境需使用WSGI服务器 (Gunicorn)+ 反向代理(Nginx):
(1)使用Gunicorn启动Flask应用
安装:pip install gunicorn
创建wsgi.py:
python
from app import app
if __name__ == '__main__':
app.run()
启动Gunicorn:
bash
# 启动:workers是工作进程数(建议=CPU核心数*2+1),bind绑定地址和端口
gunicorn -w 4 -b 0.0.0.0:8000 wsgi:app
(2)配置Nginx反向代理
Nginx负责接收客户端请求,转发到Gunicorn,同时处理静态文件、负载均衡等:
nginx
server {
listen 80;
server_name your-domain.com; # 你的域名
# 静态文件(Flask的static文件夹)
location /static {
alias /path/to/your/project/static;
}
# 转发动态请求到Gunicorn
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
12. 进阶
- 上下文 :Flask有两种核心上下文------应用上下文(
app_context)和请求上下文(request_context),request/session属于请求上下文,current_app/g属于应用上下文;current_app:当前运行的应用实例;g:全局临时存储,仅在当前请求有效,用于在钩子函数和视图函数间传递数据。
- 信号 :Flask-Signals(需安装
blinker),用于监听应用事件(如请求开始/结束、模板渲染完成等),实现解耦的事件通知; - 测试 :使用
pytest+flask.test_client()编写单元测试,模拟请求并验证响应。
- Flask是轻量级Python Web框架,核心极简但可通过扩展实现复杂功能,适合小型项目/快速原型开发;
- 核心知识点包括:路由映射、请求/响应处理、Jinja2模板、Session/Cookie、蓝图(模块化)、配置管理、钩子函数;
- 生产环境需使用Gunicorn(WSGI服务器)+ Nginx(反向代理)部署,避免使用开发服务器;扩展是Flask生态的核心,Flask-SQLAlchemy、Flask-WTF等可大幅提升开发效率。