前言
在 Python Web 开发领域,Flask 凭借其轻量、灵活、易用的特性成为了开发者的首选框架之一,尤其适合 Web 开发初学者和快速原型开发场景。作为一款 "微框架",Flask 本身仅提供构建 Web 应用的核心功能,不强制固定的项目结构,让开发者能够专注于业务逻辑的实现,同时又可以通过丰富的扩展库实现高级功能的拓展。本文将从 Flask 框架的基础概念出发,逐步讲解路由、模板引擎、表单处理等核心功能,最后通过实战案例实现一个简单的博客应用,并介绍项目部署的相关知识,帮助大家快速上手 Flask 开发。
一、Flask 框架核心概述
1.1 框架定位与核心依赖
Flask 是基于 Python 开发的轻量级 Web 微框架,设计理念围绕简洁性和灵活性展开,适用于中小型 Web 应用开发和快速原型搭建。其核心功能依赖两个关键的 Python 库,二者共同支撑起 Flask 的基础能力:
表格
| 依赖库 | 核心作用 |
|---|---|
| Werkzeug | 底层核心库,提供 WSGI 接口、HTTP 请求 / 响应处理、路由匹配等基础 Web 功能 |
| Jinja2 | 强大的模板引擎,实现 Python 代码与 HTML 页面分离,支持动态生成 HTML 内容 |
Flask 的 "微" 并不代表功能薄弱,而是指其核心体积小、无冗余,开发者可根据项目需求自由选择扩展库(如 Flask-WTF 处理表单、Flask-SQLAlchemy 操作数据库),实现按需扩展,让项目结构更轻量化。
1.2 安装 Flask
Flask 的安装非常简单,通过 Python 的包管理工具pip即可完成,同时为了提升安装速度,推荐配置国内镜像源(阿里 / 华为),以下是完整的安装步骤:
1. 配置国内镜像源(二选一)
阿里 PyPI 源
pip3 config set global.index-url http://mirrors.aliyun.com/pypi/simple
pip3 config set install.trusted-host mirrors.aliyun.com
华为 PyPI 源
pip3 config set global.index-url http://mirrors.huaweicloud.com/repository/pypi/simple
pip3 config set install.trusted-host mirrors.huaweicloud.com
2. 升级 pip(可选,推荐)
Python3 -m pip install --upgrade pip
3. 安装 Flask
pip3 install flask
安装完成后,可通过创建简单的 Flask 应用验证安装是否成功,具体代码见下文。
二、第一个 Flask 应用:Hello World
2.1 核心代码实现
创建名为app.py的文件,写入以下代码,这是一个最基础的 Flask 应用,实现了访问根路径返回 "Hello, World!" 的功能:
from flask import Flask
# 创建Flask应用实例,__name__参数用于确定应用的根路径
app = Flask(__name__)
# 定义路由:访问根路径(/)时触发hello_world视图函数
@app.route('/')
def hello_world():
# 返回HTTP响应内容,支持文本或HTML字符串
return 'Hello, World!\n'
# 应用程序入口点
if __name__ == '__main__':
# 启动开发服务器,监听所有网络接口,端口5000,开启调试模式
app.run(host='0.0.0.0', port=5000, debug=True)
2.2 代码核心解析
Flask 应用的核心组成部分在这个简单的示例中已全部体现,关键参数和装饰器的作用如下表所示:
表格
| 核心代码 | 功能说明 |
|---|---|
app = Flask(__name__) |
创建 Flask 应用实例,__name__帮助 Flask 识别模块名称,确定配置文件、模板文件的根路径 |
@app.route('/') |
路由装饰器,建立 URL 路径与视图函数的映射关系,/表示网站根路径 |
def hello_world(): |
视图函数,处理用户的 HTTP 请求,返回响应内容给客户端 |
app.run(...) |
启动 Flask 开发服务器,host=0.0.0.0允许外部设备访问,port指定端口,debug=True开启调试模式 |
2.3 运行与访问应用
-
运行应用 :在命令行中进入
app.py所在目录,执行以下命令:python3 app.py -
访问应用 :打开浏览器,输入地址
http://127.0.0.1:5000/或http://你的IP地址:5000/,页面将显示Hello, World!,表示应用运行成功。
调试模式说明 :debug=True是开发阶段的重要配置,开启后修改代码无需手动重启服务器,代码会自动重载;同时当程序出错时,浏览器会显示详细的错误信息,方便问题排查。注意:生产环境中必须关闭调试模式,避免泄露项目信息。
三、Flask 核心功能:路由与视图函数
路由是 Flask 的核心特性之一,其作用是将用户访问的 URL 路径与对应的视图函数绑定,用户发起请求时,Flask 会根据 URL 匹配对应的视图函数并执行,最终将执行结果作为响应返回。Flask 的路由系统支持静态路由、动态路由 ,并可指定HTTP 请求方法,满足不同的业务需求。
3.1 静态路由
静态路由即固定的 URL 路径,如前文的/、/about、/contact等,适用于页面地址固定的场景,定义方式为@app.route('固定路径'),示例如下:
from flask import Flask
app = Flask(__name__)
# 根路径
@app.route('/')
def index():
return '这是网站首页\n'
# 关于页面路径
@app.route('/about')
def about():
return '这是关于我们页面\n'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
运行后,访问http://127.0.0.1:5000/about,页面将显示 "这是关于我们页面"。
3.2 动态路由
在实际开发中,经常需要从 URL 中获取动态数据(如用户 ID、文章 ID、用户名),Flask 支持动态路由参数 ,通过<参数名>的形式定义动态路径,参数会自动传递给视图函数,实现动态数据的获取。
3.2.1 基础动态路由示例
from flask import Flask
app = Flask(__name__)
# 动态路由:<name>为动态参数,捕获URL中的任意字符串
@app.route('/greet/<name>')
def greet(name):
# 将动态参数嵌入响应内容,返回个性化问候
return f'Hello, {name}!\n'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
访问示例:
- 访问
http://127.0.0.1:5000/greet/Alice,返回Hello, Alice! - 访问
http://127.0.0.1:5000/greet/张三,返回Hello, 张三!
3.2.2 动态路由参数类型限制
默认情况下,动态路由参数会被解析为字符串类型,Flask 支持指定参数类型(如int、float、path),避免类型转换的麻烦,示例如下:
# 限制参数为整数类型,仅匹配数字ID
@app.route('/user/<int:user_id>')
def get_user(user_id):
return f'你正在访问用户ID为:{user_id} 的页面,ID类型为:{type(user_id)}\n'
# 限制参数为浮点型
@app.route('/price/<float:price>')
def show_price(price):
return f'商品价格为:{price} 元\n'
# 匹配包含斜杠的路径
@app.route('/file/<path:file_path>')
def get_file(file_path):
return f'文件路径为:{file_path}\n'
注意 :如果访问的参数类型与定义的类型不匹配,Flask 会返回404 Not Found错误,例如访问/user/abc,因abc不是整数,会触发 404。
3.3 支持多种 HTTP 请求方法
HTTP 请求方法代表了用户对服务器的操作意图,常见的有GET(获取数据)、POST(提交数据)、PUT(更新数据)、DELETE(删除数据)等。Flask 的路由默认仅支持GET请求,可通过methods参数指定允许的请求方法,满足表单提交、数据上传等场景。
3.3.1 仅支持 POST 请求的路由
from flask import Flask
app = Flask(__name__)
# 定义仅接受POST请求的路由,处理表单提交
@app.route('/submit', methods=['POST'])
def submit():
# 实际开发中可添加表单数据处理、数据库操作等逻辑
return 'Form submitted successfully!\n'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
测试方式 :使用curl命令模拟 POST 请求(Windows 需安装 curl 或使用 Postman 工具):
curl -X POST 127.0.0.1:5000/submit
返回Form submitted successfully!表示请求成功;若通过浏览器直接访问(GET 请求),Flask 会返回405 Method Not Allowed错误,提示请求方法不被允许。
3.3.2 同时支持 GET 和 POST 请求
实际开发中,表单页面通常需要同时支持GET(渲染表单)和POST(提交表单)请求,示例如下:
from flask import Flask, request
app = Flask(__name__)
# 同时支持GET和POST请求
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
# GET请求:渲染登录表单页面(此处用文本模拟)
return '这是登录表单页面,请提交POST请求\n'
elif request.method == 'POST':
# POST请求:处理登录数据(获取表单参数)
username = request.form.get('username')
password = request.form.get('password')
return f'登录成功!用户名:{username},密码:{password}\n'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
测试方式:使用 curl 模拟 POST 提交表单数据:
curl -X POST -d "username=admin&password=123456" 127.0.0.1:5000/login
返回登录成功!用户名:admin,密码:123456,表示数据获取和处理成功。
3.4 路由与视图函数的核心原则
- 一个路由只能绑定一个视图函数,多个路由可绑定同一个视图函数;
- 视图函数必须有返回值,返回值可以是文本、HTML 字符串、JSON 数据或响应对象;
- 动态路由参数名必须与视图函数的参数名一致;
- 生产环境中,建议为路由设置唯一的 URL,避免路径冲突。
四、Jinja2 模板引擎:动态渲染 HTML 页面
在 Web 开发中,若直接在视图函数中拼接 HTML 字符串,会导致代码耦合度高、维护困难。Flask 集成了Jinja2 模板引擎 ,实现了 Python 代码与 HTML 页面的分离,开发者可在模板中使用特殊的语法实现动态数据渲染,同时支持模板继承、块语法,极大提升了页面开发的效率和可维护性。
4.1 模板文件的目录结构
Flask 默认约定模板文件存放在项目根目录下的templates文件夹中,若未指定该目录,Flask 将无法找到模板文件,基础目录结构如下:
plaintext
/my_flask_app # 项目根目录
/templates # 模板文件夹(必须命名为templates)
index.html # 模板文件
app.py # Flask应用主文件
4.2 基础模板渲染:render_template 函数
Flask 提供render_template函数用于加载并渲染模板文件,同时可将 Python 中的变量、列表、字典等数据传递到模板中,模板中通过{``{ 变量名 }}的语法获取并渲染数据。
4.2.1 步骤 1:创建模板文件
在templates文件夹中创建greet.html,内容如下:
html
预览
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Flask模板示例</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1>
<p>这是由Jinja2模板引擎动态渲染的页面</p>
</body>
</html>
4.2.2 步骤 2:在视图函数中渲染模板
修改app.py,导入render_template函数,实现动态参数传递:
from flask import Flask, render_template
app = Flask(__name__)
# 动态路由传递参数到模板
@app.route('/greet/<name>')
def greet(name):
# 渲染greet.html模板,将name参数传递到模板中
return render_template('greet.html', name=name)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
4.2.3 访问效果
访问http://127.0.0.1:5000/greet/李四,页面将显示<h1>Hello, 李四!</h1>,实现了动态数据的渲染。
4.3 Jinja2 模板核心语法
Jinja2 模板引擎提供了丰富的语法,支持变量、循环、条件判断、注释等,满足各种动态页面的开发需求,核心语法如下表所示:
表格
| 语法类型 | 语法格式 | 功能说明 | 示例 |
|---|---|---|---|
| 变量渲染 | {``{ 变量名 }} |
渲染 Python 传递的变量,支持字符串、数字、列表、字典 | {``{ user.name }}、{``{ list[0] }} |
| 注释 | {# 注释内容 #} |
模板内注释,不会被渲染到 HTML 页面中 | {# 这是用户信息模块 #} |
| 条件判断 | {% if 条件 %}``{% elif 条件 %}``{% else %}``{% endif %} |
实现页面的条件渲染 | {% if age >= 18 %}<p>成年</p>{% else %}<p>未成年</p>{% endif %} |
| 循环遍历 | {% for 元素 in 可迭代对象 %}``{% endfor %} |
遍历列表、字典等可迭代对象,渲染批量数据 | {% for user in users %}<li>{``{ user.name }}</li>{% endfor %} |
| 变量赋值 | {% set 变量名 = 值 %} |
在模板中定义临时变量 | {% set title = '首页' %} |
示例 :带循环和条件判断的模板user_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户列表</title>
</head>
<body>
<h1>用户列表</h1>
{% if users|length > 0 %}
<ul>
{% for user in users %}
<li>
用户名:{{ user.name }},年龄:{{ user.age }},
{% if user.age >= 18 %}
<span style="color: green;">成年</span>
{% else %}
<span style="color: red;">未成年</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<p>暂无用户数据</p>
{% endif %}
</body>
</html>
视图函数代码:
@app.route('/users')
def user_list():
# 模拟用户数据
users = [
{'name': 'Alice', 'age': 20},
{'name': 'Bob', 'age': 17},
{'name': '张三', 'age': 25}
]
# 将用户列表传递到模板
return render_template('user_list.html', users=users)
访问http://127.0.0.1:5000/users,页面将根据用户年龄动态渲染 "成年 / 未成年" 标识,实现了复杂的动态页面逻辑。
4.4 模板继承与块语法:实现页面复用
在开发 Web 应用时,多个页面通常会有相同的布局(如导航栏、页脚、样式表),若每个页面都重复编写这些代码,会导致维护成本高。Jinja2 的模板继承 功能允许开发者创建一个基础模板(父模板) ,定义通用的页面布局,然后在子模板中继承基础模板,并覆盖需要自定义的部分,实现代码的复用。
4.4.1 步骤 1:创建基础模板 base.html
基础模板中通过{% block 块名 %}{% endblock %}定义可被覆盖的 "块",子模板可对这些块进行自定义,未被覆盖的块将使用基础模板的默认内容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 标题块,子模板可覆盖 -->
<title>{% block title %}我的网站{% endblock %}</title>
<!-- 样式块,用于引入页面专属样式 -->
{% block style %}{% endblock %}
</head>
<body>
<!-- 通用导航栏 -->
<header>
<nav>
<a href="/">首页</a> |
<a href="/about">关于我们</a> |
<a href="/contact">联系我们</a>
</nav>
</header>
<!-- 主内容块,子模板的核心内容 -->
<main style="margin: 20px 0;">
{% block content %}{% endblock %}
</main>
<!-- 通用页脚 -->
<footer style="text-align: center; color: #999;">
<p>© 2025 我的网站 版权所有</p>
</footer>
<!-- 脚本块,用于引入页面专属JS -->
{% block script %}{% endblock %}
</body>
</html>
4.4.2 步骤 2:创建子模板 index.html
子模板通过{% extends '基础模板名.html' %}继承基础模板,然后通过{% block 块名 %}覆盖对应的块,实现页面的自定义。
<!-- 继承base.html基础模板 -->
{% extends 'base.html' %}
<!-- 覆盖标题块 -->
{% block title %}首页 - 我的网站{% endblock %}
<!-- 覆盖样式块,添加首页专属样式 -->
{% block style %}
<style>
h2 { color: #2f54eb; }
</style>
{% endblock %}
<!-- 覆盖主内容块,添加首页核心内容 -->
{% block content %}
<h2>欢迎访问我的网站首页</h2>
<p>这是通过模板继承实现的首页,导航栏和页脚复用了基础模板的内容</p>
{% endblock %}
4.4.3 步骤 3:创建子模板 about.html
{% extends 'base.html' %}
{% block title %}关于我们 - 我的网站{% endblock %}
{% block content %}
<h2>关于我们</h2>
<p>这是关于我们页面,专注于Python Web开发分享</p>
<p>使用Flask框架构建,基于Jinja2模板引擎实现页面复用</p>
{% endblock %}
4.4.4 视图函数代码
from flask import Flask, render_template
app = Flask(__name__)
# 首页
@app.route('/')
def index():
return render_template('index.html')
# 关于我们
@app.route('/about')
def about():
return render_template('about.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
4.4.5 实现效果
访问/和/about页面,两个页面共享导航栏和页脚,同时拥有各自的标题和核心内容,实现了页面布局的复用,极大减少了代码冗余。
模板继承核心原则:
- 子模板必须以
{% extends %}开头,且只能继承一个基础模板; - 基础模板中的
block块可以嵌套,子模板可按需覆盖; - 子模板中可通过
{``{ super() }}调用基础模板中块的默认内容,实现内容补充。
五、Flask 表单处理与数据验证
Web 应用的核心交互之一是获取用户的输入数据,表单是最常用的方式。Flask 本身处理表单的能力有限,推荐使用Flask-WTF 扩展,它基于 WTForms 构建,简化了表单的创建、提交和数据验证流程,同时内置CSRF 保护,有效防止跨站请求伪造攻击。
5.1 安装 Flask-WTF
pip3 install flask-wtf
5.2 表单处理的核心流程
- 创建表单类,定义表单字段和验证规则;
- 在视图函数中实例化表单对象,支持 GET 和 POST 请求;
- 创建模板文件,渲染表单字段并添加 CSRF 令牌;
- 验证表单提交的数据,通过后进行业务处理,失败则重新渲染表单。
5.3 实战:创建一个简单的姓名提交表单
5.3.1 步骤 1:编写 Flask 应用代码(biaodan.py)
from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Length
# 创建Flask应用实例
app = Flask(__name__)
# 配置CSRF保护密钥,生产环境中需使用随机的强密钥(如os.urandom(24))
app.secret_key = 's3cr3t_123456'
# 定义表单类,继承自FlaskForm
class NameForm(FlaskForm):
# 定义文本字段:标签名、验证规则(必填、长度2-50)
name = StringField('你的姓名', validators=[
DataRequired(message='姓名不能为空!'),
Length(min=2, max=50, message='姓名长度必须在2-50个字符之间')
])
# 定义提交按钮
submit = SubmitField('提交')
# 定义路由,支持GET和POST请求
@app.route('/', methods=['GET', 'POST'])
def index():
# 实例化表单对象
form = NameForm()
# 验证表单:是否为POST请求且数据通过所有验证规则
if form.validate_on_submit():
# 获取表单提交的姓名数据
username = form.name.data
# 清空表单输入框
form.name.data = ''
# 传递用户名到模板,显示成功信息
return render_template('index.html', form=form, username=username)
# GET请求或表单验证失败,渲染表单
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
5.3.2 步骤 2:创建表单模板文件(templates/index.html)
模板中通过form.字段名()渲染表单控件,{``{ form.csrf_token }}添加 CSRF 令牌(必须添加,否则表单提交会失败),同时通过form.字段名.errors获取验证失败的提示信息。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Flask表单示例</title>
<style>
.error { color: red; font-size: 12px; }
form { margin: 20px 0; }
label { display: inline-block; width: 80px; }
input { padding: 5px; width: 200px; }
button { padding: 5px 15px; margin-left: 85px; }
</style>
</head>
<body>
<h1>姓名提交表单</h1>
<form method="POST">
<!-- CSRF令牌,必须添加 -->
{{ form.csrf_token }}
<!-- 渲染姓名标签和输入框 -->
{{ form.name.label }} {{ form.name() }}
<!-- 显示姓名字段的验证错误信息 -->
{% if form.name.errors %}
{% for error in form.name.errors %}
<p class="error">{{ error }}</p>
{% endfor %}
{% endif %}
<br>
<!-- 渲染提交按钮 -->
{{ form.submit() }}
</form>
<!-- 显示表单提交成功的信息 -->
{% if username %}
<h2 style="color: green;">提交成功!你好,{{ username }}!</h2>
{% endif %}
</body>
</html>
5.3.3 运行与测试
- 执行命令
python3 biaodan.py启动应用; - 访问
http://127.0.0.1:5000/,进行以下测试:- 直接点击提交:显示 "姓名不能为空!";
- 输入 1 个字符(如 "张"):显示 "姓名长度必须在 2-50 个字符之间";
- 输入合法姓名(如 "张三"):提交成功,显示 "提交成功!你好,张三!"。
5.4 常用的表单验证器
WTForms 提供了丰富的内置验证器,满足大部分数据验证需求,常用验证器如下表所示:
表格
| 验证器 | 功能说明 | 示例 |
|---|---|---|
| DataRequired() | 验证字段是否为空,支持自定义提示信息 | DataRequired (message=' 字段不能为空 ') |
| Length(min, max) | 验证字段长度在 min 和 max 之间 | Length (min=6, max=20, message=' 长度 6-20') |
| Email() | 验证字段是否为合法的邮箱地址 | Email (message=' 请输入合法邮箱 ') |
| EqualTo('field') | 验证两个字段值是否一致(如密码和确认密码) | EqualTo ('password', message=' 两次密码不一致 ') |
| NumberRange(min, max) | 验证数字字段在指定范围内 | NumberRange (min=0, max=100, message='0-100 之间 ') |
| Regexp() | 通过正则表达式验证字段 | Regexp (r'^[0-9a-zA-Z]+$', message=' 仅支持数字和字母 ') |
5.5 手动获取表单数据
若无需复杂的验证规则,也可通过 Flask 的request对象手动获取表单数据,适用于简单的表单场景,示例如下:
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 通过request.form.get()获取表单数据,避免键不存在报错
username = request.form.get('username', '')
password = request.form.get('password', '')
if username == 'admin' and password == '123456':
return '登录成功!'
else:
return '用户名或密码错误!'
return render_template('login.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
注意:手动获取表单数据时,需要自己编写验证逻辑,且无 CSRF 保护,生产环境中建议使用 Flask-WTF。
六、Flask 项目结构与生产环境部署
6.1 规范的 Flask 项目结构
前面的示例均为单文件应用,适用于简单的功能开发。当项目复杂度提升时,单文件会导致代码难以维护,因此需要遵循模块化 的原则,将不同功能的代码拆分到不同的文件和文件夹中。以下是典型的 Flask 项目结构,适用于大部分中小型 Flask 应用:
plaintext
/my_flask_app # 项目根目录
/app # 应用核心目录
/templates # 模板文件夹
index.html # 模板文件
base.html # 基础模板
/static # 静态文件文件夹
/css # 样式表文件夹
style.css # 样式文件
/js # JavaScript文件夹
script.js # JS文件
/images # 图片文件夹
__init__.py # 应用初始化文件,创建Flask实例、配置扩展
routes.py # 路由与视图函数文件
forms.py # 表单类定义文件
models.py # 数据库模型文件(可选,如使用Flask-SQLAlchemy)
run.py # 项目启动文件
requirements.txt # 项目依赖库清单
6.1.1 核心文件说明
-
app/init.py :应用的入口,创建 Flask 实例并配置扩展,示例如下:
from flask import Flask from flask_wtf import CSRFProtect # 初始化CSRF保护 csrf = CSRFProtect() def create_app(): # 创建Flask应用实例 app = Flask(__name__) # 配置密钥 app.secret_key = 's3cr3t_123456' # 初始化扩展 csrf.init_app(app) # 注册路由蓝图(后续可通过蓝图管理路由) from .routes import main_bp app.register_blueprint(main_bp) return app -
app/routes.py :存放所有路由和视图函数,使用蓝图(Blueprint)管理,示例如下:
from flask import Blueprint, render_template from .forms import NameForm # 创建蓝图实例 main_bp = Blueprint('main', __name__) # 定义路由,使用蓝图的route装饰器 @main_bp.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): username = form.name.data form.name.data = '' return render_template('index.html', form=form, username=username) return render_template('index.html', form=form) -
run.py :项目启动文件,调用
create_app()创建应用实例并启动,示例如下:from app import create_app # 创建应用实例 app = create_app() if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=False) -
requirements.txt :记录项目依赖的库和版本,方便他人部署,生成命令:
pip3 freeze > requirements.txt安装依赖的命令:
pip3 install -r requirements.txt
6.2 Flask 应用的生产环境部署
Flask 自带的开发服务器(app.run())仅适用于开发阶段,不支持高并发、稳定性差 ,无法满足生产环境的需求。生产环境中,通常采用 **"WSGI 服务器 + 反向代理服务器"的架构部署 Flask 应用,常用的组合是Gunicorn + Nginx**。
6.2.1 部署架构说明
- Gunicorn:Python WSGI HTTP 服务器,负责运行 Flask 应用,处理动态请求,支持多进程、多线程,提升并发处理能力;
- Nginx:高性能的 HTTP 和反向代理服务器,作为前端服务器,负责处理静态文件请求(CSS、JS、图片),将动态请求转发到 Gunicorn,同时支持负载均衡、HTTPS 配置等。
6.2.2 部署步骤(基于 Linux 服务器)
步骤 1:安装 Gunicorn
pip3 install gunicorn
步骤 2:使用 Gunicorn 启动 Flask 应用
在项目根目录下,执行以下命令启动应用:
# 基本启动:2个工作线程,绑定127.0.0.1:8000
gunicorn -w 2 -b 127.0.0.1:8000 run:app
# 后台启动:添加-D参数,日志输出到gunicorn.log
gunicorn -w 4 -b 127.0.0.1:8000 -D --access-logfile gunicorn.log run:app
参数说明:
-w:工作进程数,推荐设置为CPU核心数 * 2 + 1;-b:绑定的 IP 和端口,生产环境中建议绑定本地 IP(127.0.0.1),通过 Nginx 转发;-D:后台运行;--access-logfile:指定访问日志文件;run:app:run是启动文件名称(run.py),app是文件中的 Flask 应用实例。
步骤 3:安装并配置 Nginx
-
安装 Nginx (以 CentOS 为例):
yum install -y nginx -
启动 Nginx :
systemctl start nginx systemctl enable nginx # 设置开机自启 -
配置 Nginx 反向代理 :编辑 Nginx 配置文件
/etc/nginx/nginx.conf,或在/etc/nginx/conf.d/下创建自定义配置文件flask_app.conf,内容如下:nginx
server { listen 80; # 监听80端口 server_name your_domain.com; # 你的域名或服务器IP # 处理静态文件请求,转发到Flask的static文件夹 location /static/ { alias /path/to/your/project/app/static/; # 静态文件的绝对路径 expires 30d; # 静态文件缓存30天 } # 处理动态请求,转发到Gunicorn location / { proxy_pass http://127.0.0.1:8000; # Gunicorn的地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } -
检查配置并重启 Nginx :
nginx -t # 检查配置文件是否有错误 systemctl restart nginx # 重启Nginx
步骤 4:访问应用
配置完成后,直接在浏览器中输入服务器 IP 或域名(如http://your_domain.com),即可访问部署的 Flask 应用,Nginx 会自动处理静态文件和动态请求的转发。
6.2.3 部署注意事项
- 生产环境中,必须关闭 Flask 的调试模式 (
debug=False),避免泄露项目代码和配置信息; - 密钥(
secret_key)需使用随机的强密钥,可通过python3 -c "import os; print(os.urandom(24))"生成; - 建议使用虚拟环境(如 venv、conda)隔离项目依赖,避免与系统 Python 环境冲突;
- 可通过
systemctl管理 Gunicorn 进程,实现开机自启和故障重启; - 生产环境中建议配置HTTPS,通过 Let's Encrypt 获取免费 SSL 证书,提升网站安全性。
七、实战案例:搭建一个简单的博客应用
结合前文所学的 Flask 核心知识,我们实现一个简单的博客应用,支持用户提交文章(标题 + 内容),并在页面上展示所有已提交的文章,实现 Web 应用的基础交互功能。
7.1 项目结构
本案例为轻量版博客,采用简化的项目结构,无需拆分过多文件,核心结构如下:
plaintext
/simple_blog # 项目根目录
/templates # 模板文件夹
index.html # 博客首页模板(包含表单和文章列表)
app.py # Flask应用主文件,包含路由、视图函数和数据存储
7.2 核心代码实现
7.2.1 app.py:应用主文件
from flask import Flask, render_template, request
# 创建Flask应用实例
app = Flask(__name__)
# 设置CSRF保护密钥(若使用Flask-WTF则必须配置,本案例手动处理表单,可选)
app.secret_key = 'blog_secret_123'
# 用列表存储博客文章,每篇文章为字典,模拟数据库(实际开发用真实数据库)
posts = []
# 博客首页路由,支持GET(展示页面)和POST(提交文章)
@app.route('/', methods=['GET', 'POST'])
def index():
# 处理POST请求:提交文章
if request.method == 'POST':
# 获取表单中的标题和内容,去除首尾空格
title = request.form.get('title', '').strip()
content = request.form.get('content', '').strip()
# 简单的表单验证:标题和内容不能为空
if title and content:
# 将文章添加到posts列表,按提交时间倒序(最新的在最前面)
posts.insert(0, {'title': title, 'content': content})
# 渲染模板,将文章列表传递到模板
return render_template('index.html', posts=posts)
# 启动应用
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
7.2.2 templates/index.html:博客首页模板
模板中包含文章提交表单 和文章列表展示两部分,使用 Jinja2 的循环语法遍历所有文章,实现动态渲染。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Flask简单博客</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { max-width: 1200px; margin: 0 auto; padding: 20px; font-family: Arial, sans-serif; }
h1 { color: #2f54eb; margin-bottom: 30px; }
.form-section { margin-bottom: 40px; padding: 20px; border: 1px solid #e6e6e6; border-radius: 8px; }
.form-section h2 { color: #333; margin-bottom: 20px; font-size: 18px; }
label { display: block; margin-bottom: 8px; color: #666; }
input[type="text"] { width: 100%; padding: 10px; margin-bottom: 20px; border: 1px solid #e6e6e6; border-radius: 4px; font-size: 16px; }
textarea { width: 100%; height: 150px; padding: 10px; margin-bottom: 20px; border: 1px solid #e6e6e6; border-radius: 4px; resize: vertical; font-size: 16px; }
button { padding: 10px 30px; background-color: #2f54eb; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
button:hover { background-color: #1d39c4; }
.posts-section h2 { color: #333; margin-bottom: 20px; font-size: 18px; }
.post-item { padding: 20px; border: 1px solid #e6e6e6; border-radius: 8px; margin-bottom: 20px; }
.post-item h3 { color: #2f54eb; margin-bottom: 10px; }
.post-item p { color: #666; line-height: 1.6; white-space: pre-wrap; }
.no-post { color: #999; text-align: center; padding: 40px; border: 1px dashed #e6e6e6; border-radius: 8px; }
</style>
</head>
<body>
<h1>Flask简单博客</h1>
<!-- 文章提交表单 -->
<div class="form-section">
<h2>发布新文章</h2>
<form method="POST">
<label for="title">文章标题</label>
<input type="text" id="title" name="title" required placeholder="请输入文章标题">
<label for="content">文章内容</label>
<textarea id="content" name="content" required placeholder="请输入文章内容"></textarea>
<button type="submit">发布文章</button>
</form>
</div>
<!-- 文章列表展示 -->
<div class="posts-section">
<h2>文章列表</h2>
{% if posts|length > 0 %}
{% for post in posts %}
<div class="post-item">
<h3>{{ post.title }}</h3>
<p>{{ post.content }}</p>
</div>
{% endfor %}
{% else %}
<div class="no-post">暂无文章,快来发布第一篇文章吧!</div>
{% endif %}
</div>
</body>
</html>
7.3 运行与使用
- 在项目根目录下执行命令
python3 app.py启动应用; - 访问
http://127.0.0.1:5000/,进入博客首页; - 在 "发布新文章" 区域输入标题和内容,点击 "发布文章",文章将立即显示在 "文章列表" 中;
- 可多次发布文章,最新发布的文章会显示在列表最前面。
7.4 功能扩展方向
本案例是一个基础的博客应用,实际开发中可进行以下扩展,实现更完整的功能:
- 添加用户认证(Flask-Login),实现用户注册、登录,只有登录用户才能发布文章;
- 使用数据库(Flask-SQLAlchemy + MySQL/PostgreSQL/SQLite)存储文章数据,替代列表,实现数据持久化;
- 添加文章编辑、删除功能,实现对文章的管理;
- 添加分页功能,当文章数量较多时,分页展示;
- 添加文章分类、标签功能,实现文章的分类管理;
- 添加评论功能,允许用户对文章进行评论。
八、Flask 框架的优势与适用场景
8.1 Flask 的核心优势
- 轻量灵活:核心体积小,无强制的项目结构和依赖,开发者可按需选择扩展,自由设计项目架构;
- 易于学习:API 简洁直观,入门门槛低,适合 Python 初学者学习 Web 开发,能快速上手并实现功能;
- 扩展丰富:拥有庞大的扩展生态,几乎所有 Web 开发所需的功能(表单处理、数据库操作、用户认证、缓存、邮件发送等)都有对应的扩展,且扩展集成简单;
- 兼容性好:基于 Python 开发,支持 Python3 的所有版本,可与其他 Python 库(如 Pandas、NumPy、Matplotlib)无缝集成,实现数据可视化、数据分析等功能;
- 开发效率高:支持快速原型开发,能在短时间内实现 Web 应用的核心功能,适合创业项目和小型应用的快速迭代。
8.2 Flask 的适用场景
- 小型 Web 应用开发:如个人博客、企业官网、小型管理系统等;
- 快速原型开发:创业项目初期,快速实现产品原型,验证市场需求;
- API 接口开发:结合 Flask-RESTful/Flask-RESTX 实现 RESTful API,为移动端、前端提供数据接口;
- 数据分析可视化平台:结合 Python 的数据分析库(Pandas、Matplotlib),实现数据的 Web 可视化展示;
- 自动化工具的 Web 化:将 Python 自动化脚本封装为 Web 应用,提升工具的易用性和可访问性。
注意:对于超大型、高并发的 Web 应用(如电商平台、社交平台),推荐使用 Django 等全栈框架,Django 提供了更完善的内置功能(如 ORM、后台管理、用户认证),适合大型项目的开发。
九、总结
本文从 Flask 框架的基础概念出发,逐步讲解了 Flask 的核心功能,包括环境搭建、第一个应用、路由与视图函数、Jinja2 模板引擎、表单处理与数据验证、项目结构规范、生产环境部署,并通过一个实战案例实现了简单的博客应用,让大家从理论到实践全面掌握 Flask 的基础使用。
Flask 作为一款轻量级的 Web 微框架,其核心魅力在于简洁性和灵活性,它不限制开发者的开发方式,让开发者能够专注于业务逻辑的实现,同时又能通过丰富的扩展库实现功能的无限拓展。对于 Web 开发初学者来说,学习 Flask 不仅能掌握 Web 开发的基本流程和核心概念,还能培养模块化、工程化的开发思维,为后续学习更复杂的框架(如 Django)打下坚实的基础。
学习 Flask 的关键在于多实践、多尝试 ,建议大家在本文的基础上,尝试扩展博客案例的功能,如添加数据库、用户认证、分页等,在实践中加深对 Flask 的理解。同时,Flask 的官方文档(https://flask.palletsprojects.com/)是最权威的学习资料,建议大家结合官方文档进行深入学习。
希望本文能帮助大家快速入门 Flask 框架,开启 Python Web 开发的之旅!如果在学习过程中有任何问题,欢迎在评论区交流讨论。
附:Flask 常用扩展库清单
表格
| 扩展库 | 功能说明 | 安装命令 |
|---|---|---|
| Flask-WTF | 表单处理与 CSRF 保护 | pip3 install flask-wtf |
| Flask-SQLAlchemy | 数据库 ORM 操作 | pip3 install flask-sqlalchemy |
| Flask-Login | 用户认证与登录管理 | pip3 install flask-login |
| Flask-Migrate | 数据库迁移(基于 Alembic) | pip3 install flask-migrate |
| Flask-Mail | 邮件发送功能 | pip3 install flask-mail |
| Flask-Cache | 缓存功能 | pip3 install flask-cache |
| Flask-RESTful | 构建 RESTful API | pip3 install flask-restful |
| Flask-Bootstrap | 集成 Bootstrap 前端框架 | pip3 install flask-bootstrap |
| Flask-Session | 会话管理,支持服务器端会话 |