Flask :轻量级 Python Web 框架
Flask 是一个基于 Python 的轻量级 Web 应用框架 ,遵循 "微框架"(Microframework) 理念,核心仅依赖两个库:Werkzeug (处理 HTTP 请求和路由)和Jinja2(模板引擎),其余功能通过丰富的扩展生态实现。它以简洁、灵活和可扩展性著称,适合从简单 API 到复杂 Web 应用的各种场景。
一、Flask 核心概念与特点
1.1 核心组件
| 组件 | 作用 |
|---|---|
| Werkzeug | WSGI 工具库,处理请求响应、路由匹配、会话管理 |
| Jinja2 | 模板引擎,支持模板继承、变量替换、控制流 |
| Click | 命令行工具,用于创建和管理 Flask 应用 |
1.2 微框架理念
Flask 的 "微" 并非指功能少,而是指:
- 核心代码精简,只保留 Web 开发的最基础功能
- 不强制使用特定工具或库,给予开发者完全自由
- 不内置 ORM、用户认证、表单处理等功能,通过扩展按需添加
- 遵循 "约定优于配置",但保持高度灵活性
1.3 主要特点
- 轻量级:核心代码少,学习曲线平缓,适合快速上手
- 灵活性:可根据需求选择组件,自由定制架构
- 可扩展:拥有丰富的官方和社区扩展,覆盖几乎所有 Web 开发需求
- RESTful 友好:内置支持 RESTful API 开发,可轻松构建 API 服务
- 开发效率高:内置开发服务器和调试器,支持热重载
- 测试简单:内置测试客户端,便于编写单元测试和集成测试
二、安装与环境配置
2.1 基本安装
bash
# 创建虚拟环境(推荐)
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
# 安装Flask
pip install flask
2.2 第一个 Flask 应用(Hello World)
python
# app.py
from flask import Flask
app = Flask(__name__) # 创建Flask应用实例
@app.route('/') # 路由装饰器,绑定URL路径到视图函数
def hello_world():
return 'Hello, Flask!' # 返回响应
if __name__ == '__main__':
app.run(debug=True) # 运行开发服务器,开启调试模式
运行应用:
bash
python app.py
# 访问 http://127.0.0.1:5000
三、Flask 核心功能详解
3.1 路由系统
路由是 Flask 的核心,用于将 URL 路径映射到视图函数。
3.1.1 基础路由
python
# 静态路由
@app.route('/about')
def about():
return 'About Page'
# 动态路由(字符串参数)
@app.route('/user/<username>')
def show_user(username):
return f'User: {username}'
# 动态路由(指定类型)
@app.route('/post/<int:post_id>') # int、float、path(接受斜杠)
def show_post(post_id):
return f'Post ID: {post_id}'
3.1.2 HTTP 方法
默认只支持 GET 方法,可通过methods参数指定多种 HTTP 方法:
python
from flask import request
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 处理表单提交
username = request.form['username']
password = request.form['password']
return f'Login attempt for {username}'
else:
# 显示登录表单
return '''
<form method="post">
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<input type="submit" value="Login">
</form>
'''
3.1.3 URL 构建(url_for)
使用url_for()函数根据视图函数名生成 URL,避免硬编码:
python
from flask import url_for
@app.route('/')
def index():
# 生成about页面的URL
about_url = url_for('about')
# 生成带参数的URL
user_url = url_for('show_user', username='Alice')
return f'''
<a href="{about_url}">About</a><br>
<a href="{user_url}">User Alice</a>
'''
3.2 视图函数与响应
3.2.1 视图函数返回值类型
视图函数可以返回多种类型的响应:
python
# 1. 字符串(自动包装为Response对象)
@app.route('/string')
def return_string():
return 'Hello, Flask!'
# 2. 元组(响应内容, 状态码, 响应头)
@app.route('/tuple')
def return_tuple():
return 'Not Found', 404, {'Content-Type': 'text/plain'}
# 3. Response对象(完全控制响应)
from flask import Response
@app.route('/response')
def return_response():
response = Response('Custom Response', status=200)
response.headers['X-Custom-Header'] = 'Flask'
return response
# 4. JSON数据(自动设置Content-Type为application/json)
@app.route('/json')
def return_json():
return {'name': 'Alice', 'age': 30}
3.2.2 重定向与错误处理
python
from flask import redirect, abort
# 重定向
@app.route('/old')
def old_page():
return redirect(url_for('new_page'))
@app.route('/new')
def new_page():
return 'This is the new page'
# 错误处理
@app.errorhandler(404)
def page_not_found(error):
return 'Page not found!', 404
# 主动触发错误
@app.route('/error')
def trigger_error():
abort(404) # 立即返回404错误
3.3 请求处理(request 对象)
Flask 通过request对象封装客户端请求信息,该对象是上下文局部变量,仅在请求处理期间有效:
python
from flask import request
@app.route('/request-info')
def request_info():
return f'''
Method: {request.method}<br>
URL: {request.url}<br>
Args: {request.args}<br> # 查询参数(?key=value)
Form: {request.form}<br> # 表单数据
Headers: {request.headers.get('User-Agent')}<br>
Cookies: {request.cookies.get('session_id')}<br>
'''
3.4 模板系统(Jinja2)
Flask 集成 Jinja2 模板引擎,支持动态生成 HTML 页面。
3.4.1 基本用法
创建模板文件(默认存放在templates目录)
html
<!-- templates/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1>
{% if user %}
<p>Welcome back, {{ user.username }}!</p>
{% else %}
<p>Please log in.</p>
{% endif %}
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
渲染模板
python
from flask import render_template
@app.route('/template')
def render_template_example():
return render_template(
'index.html',
title='Flask Template Demo',
name='Alice',
user={'username': 'alice123'},
items=['Apple', 'Banana', 'Cherry']
)
3.4.2 模板继承
Jinja2 支持模板继承,减少代码重复:
html
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My App{% endblock %}</title>
</head>
<body>
<header>{% block header %}<h1>My App</h1>{% endblock %}</header>
<main>{% block content %}{% endblock %}</main>
<footer>{% block footer %}© 2026 My App{% endblock %}</footer>
</body>
</html>
<!-- templates/home.html -->
{% extends "base.html" %}
{% block title %}Home - My App{% endblock %}
{% block content %}
<p>Welcome to the home page!</p>
{% endblock %}
3.5 会话管理(session 对象)
Flask 使用session对象实现用户会话,基于加密 Cookie:
python
from flask import session, redirect, url_for, request
app.secret_key = 'your-secret-key-here' # 必须设置密钥用于加密会话数据
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
session['username'] = username # 存储会话数据
return redirect(url_for('dashboard'))
return '''
<form method="post">
Username: <input type="text" name="username"><br>
<input type="submit" value="Login">
</form>
'''
@app.route('/dashboard')
def dashboard():
if 'username' in session:
return f'Welcome, {session["username"]}! <a href="/logout">Logout</a>'
return redirect(url_for('login'))
@app.route('/logout')
def logout():
session.pop('username', None) # 删除会话数据
return redirect(url_for('login'))
四、Flask 扩展生态
Flask 的强大之处在于其丰富的扩展生态,以下是常用扩展:
| 扩展名称 | 功能 |
|---|---|
| Flask-SQLAlchemy | ORM 工具,支持 SQLite、MySQL、PostgreSQL 等数据库 |
| Flask-WTF | 表单处理与验证,集成 WTForms |
| Flask-Login | 用户认证系统,管理用户登录状态 |
| Flask-Mail | 邮件发送功能 |
| Flask-RESTful | 简化 RESTful API 开发 |
| Flask-Babel | 国际化与本地化支持 |
| Flask-Admin | 快速创建管理后台 |
| Flask-CORS | 处理跨域资源共享 (CORS) 问题 |
4.1 扩展使用示例(Flask-SQLAlchemy)
python
# 安装扩展
pip install flask-sqlalchemy
# 应用代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mydb.db' # SQLite数据库
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 shell中执行)
with app.app_context():
db.create_all()
# 数据库操作示例
@app.route('/add-user/<username>/<email>')
def add_user(username, email):
new_user = User(username=username, email=email)
db.session.add(new_user)
db.session.commit()
return f'User {username} added!'
@app.route('/users')
def get_users():
users = User.query.all()
return '<br>'.join([f'{user.username}: {user.email}' for user in users])
五、Flask 高级特性
5.1 应用工厂模式
应用工厂模式允许创建多个应用实例,适合测试和配置不同环境:
py
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app(config_name='development'):
app = Flask(__name__)
# 根据配置名称加载不同配置
if config_name == 'development':
app.config.from_object('config.DevelopmentConfig')
elif config_name == 'production':
app.config.from_object('config.ProductionConfig')
db.init_app(app) # 初始化扩展
# 注册蓝图
from app.main import bp as main_bp
app.register_blueprint(main_bp)
return app
# config.py
class Config:
SECRET_KEY = 'your-secret-key'
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'postgresql://user:password@localhost/prod_db'
5.2 蓝图(Blueprints)
蓝图用于组织大型应用的路由和视图,实现模块化开发:
python
# app/main/__init__.py
from flask import Blueprint
bp = Blueprint('main', __name__)
# app/main/routes.py
from flask import render_template
from app.main import bp
@bp.route('/')
def index():
return render_template('index.html')
@bp.route('/about')
def about():
return render_template('about.html')
5.3 上下文管理器
Flask 有两种主要上下文:
- 应用上下文 :存储应用级数据(
current_app,g) - 请求上下文 :存储请求级数据(
request,session)
python
from flask import Flask, current_app, g
app = Flask(__name__)
app.config['DATABASE'] = 'mydb.db'
def get_db():
if 'db' not in g:
# 假设这里创建数据库连接
g.db = f"Connected to {current_app.config['DATABASE']}"
return g.db
@app.route('/db')
def db_info():
return get_db()
六、Flask 部署与最佳实践
6.1 部署选项
Flask 开发服务器仅用于开发环境,生产环境需要使用专业 WSGI 服务器:
| 服务器 | 特点 |
|---|---|
| Gunicorn | 纯 Python WSGI 服务器,简单易用 |
| uWSGI | 高性能 WSGI 服务器,支持多种协议 |
| Gevent | 基于协程的异步服务器,适合高并发 |
部署步骤:
- 安装生产服务器:
pip install gunicorn - 创建启动脚本:
gunicorn -w 4 -b 0.0.0.0:8000 "app:create_app()" - 配合 Nginx 作为反向代理,处理静态文件和负载均衡
6.2 最佳实践
-
项目结构:使用蓝图和应用工厂模式组织代码
-
环境分离:开发、测试、生产环境使用不同配置
-
安全措施
- 设置强密钥(
SECRET_KEY) - 启用 CSRF 保护(Flask-WTF)
- 验证用户输入,防止 SQL 注入和 XSS 攻击
- 使用 HTTPS
- 设置强密钥(
-
性能优化
- 使用缓存(Flask-Caching)
- 数据库查询优化
- 异步任务处理(Celery)
-
日志记录:配置完善的日志系统,便于问题排查
七、Flask vs Django:如何选择
| 对比项 | Flask | Django |
|---|---|---|
| 设计理念 | 微框架,轻量级,灵活自由 | 全栈框架,"电池已包含",约定优于配置 |
| 内置功能 | 仅核心功能,其他通过扩展实现 | 内置 ORM、Admin、认证、表单等全套功能 |
| 灵活性 | 极高,可自由选择组件 | 中等,遵循 Django 约定 |
| 学习曲线 | 平缓,适合初学者 | 陡峭,概念较多 |
| 适用场景 | 小型应用、API 服务、微服务、快速原型 | 中大型应用、CMS、电商平台、企业级系统 |
八、快速入门:创建 RESTful API 示例
以下是一个完整的 Flask RESTful API 示例,使用 Flask-RESTful 扩展:
python
# 安装扩展
pip install flask flask-restful flask-sqlalchemy
# app.py
from flask import Flask, request
from flask_restful import Api, Resource, fields, marshal_with
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///api.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
api = Api(app)
db = SQLAlchemy(app)
# 模型定义
class Task(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
description = db.Column(db.String(200))
done = db.Column(db.Boolean, default=False)
# 序列化字段
resource_fields = {
'id': fields.Integer,
'title': fields.String,
'description': fields.String,
'done': fields.Boolean
}
# API资源
class TaskList(Resource):
@marshal_with(resource_fields)
def get(self):
tasks = Task.query.all()
return tasks
@marshal_with(resource_fields)
def post(self):
data = request.json
new_task = Task(title=data['title'], description=data.get('description'))
db.session.add(new_task)
db.session.commit()
return new_task, 201
class TaskResource(Resource):
@marshal_with(resource_fields)
def get(self, task_id):
task = Task.query.get_or_404(task_id)
return task
@marshal_with(resource_fields)
def put(self, task_id):
task = Task.query.get_or_404(task_id)
data = request.json
task.title = data.get('title', task.title)
task.description = data.get('description', task.description)
task.done = data.get('done', task.done)
db.session.commit()
return task
def delete(self, task_id):
task = Task.query.get_or_404(task_id)
db.session.delete(task)
db.session.commit()
return '', 204
# 注册资源
api.add_resource(TaskList, '/tasks')
api.add_resource(TaskResource, '/tasks/<int:task_id>')
# 创建数据库
with app.app_context():
db.create_all()
if __name__ == '__main__':
app.run(debug=True)