零基础入门 Flask 框架

前言

在 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 运行与访问应用

  1. 运行应用 :在命令行中进入app.py所在目录,执行以下命令:

    复制代码
    python3 app.py
  2. 访问应用 :打开浏览器,输入地址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 支持指定参数类型(如intfloatpath),避免类型转换的麻烦,示例如下:

复制代码
# 限制参数为整数类型,仅匹配数字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 路由与视图函数的核心原则

  1. 一个路由只能绑定一个视图函数,多个路由可绑定同一个视图函数;
  2. 视图函数必须有返回值,返回值可以是文本、HTML 字符串、JSON 数据或响应对象;
  3. 动态路由参数名必须与视图函数的参数名一致;
  4. 生产环境中,建议为路由设置唯一的 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>&copy; 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页面,两个页面共享导航栏和页脚,同时拥有各自的标题和核心内容,实现了页面布局的复用,极大减少了代码冗余。

模板继承核心原则

  1. 子模板必须以{% extends %}开头,且只能继承一个基础模板;
  2. 基础模板中的block块可以嵌套,子模板可按需覆盖;
  3. 子模板中可通过{``{ super() }}调用基础模板中块的默认内容,实现内容补充。

五、Flask 表单处理与数据验证

Web 应用的核心交互之一是获取用户的输入数据,表单是最常用的方式。Flask 本身处理表单的能力有限,推荐使用Flask-WTF 扩展,它基于 WTForms 构建,简化了表单的创建、提交和数据验证流程,同时内置CSRF 保护,有效防止跨站请求伪造攻击。

5.1 安装 Flask-WTF

复制代码
pip3 install flask-wtf

5.2 表单处理的核心流程

  1. 创建表单类,定义表单字段和验证规则;
  2. 在视图函数中实例化表单对象,支持 GET 和 POST 请求;
  3. 创建模板文件,渲染表单字段并添加 CSRF 令牌;
  4. 验证表单提交的数据,通过后进行业务处理,失败则重新渲染表单。

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 运行与测试
  1. 执行命令python3 biaodan.py启动应用;
  2. 访问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 核心文件说明
  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
  2. 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)
  3. 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)
  4. 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:apprun是启动文件名称(run.py),app是文件中的 Flask 应用实例。
步骤 3:安装并配置 Nginx
  1. 安装 Nginx (以 CentOS 为例):

    复制代码
    yum install -y nginx
  2. 启动 Nginx

    复制代码
    systemctl start nginx
    systemctl enable nginx  # 设置开机自启
  3. 配置 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;
        }
    }
  4. 检查配置并重启 Nginx

    复制代码
    nginx -t  # 检查配置文件是否有错误
    systemctl restart nginx  # 重启Nginx
步骤 4:访问应用

配置完成后,直接在浏览器中输入服务器 IP 或域名(如http://your_domain.com),即可访问部署的 Flask 应用,Nginx 会自动处理静态文件和动态请求的转发。

6.2.3 部署注意事项
  1. 生产环境中,必须关闭 Flask 的调试模式debug=False),避免泄露项目代码和配置信息;
  2. 密钥(secret_key)需使用随机的强密钥,可通过python3 -c "import os; print(os.urandom(24))"生成;
  3. 建议使用虚拟环境(如 venv、conda)隔离项目依赖,避免与系统 Python 环境冲突;
  4. 可通过systemctl管理 Gunicorn 进程,实现开机自启和故障重启;
  5. 生产环境中建议配置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 运行与使用

  1. 在项目根目录下执行命令python3 app.py启动应用;
  2. 访问http://127.0.0.1:5000/,进入博客首页;
  3. 在 "发布新文章" 区域输入标题和内容,点击 "发布文章",文章将立即显示在 "文章列表" 中;
  4. 可多次发布文章,最新发布的文章会显示在列表最前面。

7.4 功能扩展方向

本案例是一个基础的博客应用,实际开发中可进行以下扩展,实现更完整的功能:

  1. 添加用户认证(Flask-Login),实现用户注册、登录,只有登录用户才能发布文章;
  2. 使用数据库(Flask-SQLAlchemy + MySQL/PostgreSQL/SQLite)存储文章数据,替代列表,实现数据持久化;
  3. 添加文章编辑、删除功能,实现对文章的管理;
  4. 添加分页功能,当文章数量较多时,分页展示;
  5. 添加文章分类、标签功能,实现文章的分类管理;
  6. 添加评论功能,允许用户对文章进行评论。

八、Flask 框架的优势与适用场景

8.1 Flask 的核心优势

  1. 轻量灵活:核心体积小,无强制的项目结构和依赖,开发者可按需选择扩展,自由设计项目架构;
  2. 易于学习:API 简洁直观,入门门槛低,适合 Python 初学者学习 Web 开发,能快速上手并实现功能;
  3. 扩展丰富:拥有庞大的扩展生态,几乎所有 Web 开发所需的功能(表单处理、数据库操作、用户认证、缓存、邮件发送等)都有对应的扩展,且扩展集成简单;
  4. 兼容性好:基于 Python 开发,支持 Python3 的所有版本,可与其他 Python 库(如 Pandas、NumPy、Matplotlib)无缝集成,实现数据可视化、数据分析等功能;
  5. 开发效率高:支持快速原型开发,能在短时间内实现 Web 应用的核心功能,适合创业项目和小型应用的快速迭代。

8.2 Flask 的适用场景

  1. 小型 Web 应用开发:如个人博客、企业官网、小型管理系统等;
  2. 快速原型开发:创业项目初期,快速实现产品原型,验证市场需求;
  3. API 接口开发:结合 Flask-RESTful/Flask-RESTX 实现 RESTful API,为移动端、前端提供数据接口;
  4. 数据分析可视化平台:结合 Python 的数据分析库(Pandas、Matplotlib),实现数据的 Web 可视化展示;
  5. 自动化工具的 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 会话管理,支持服务器端会话
相关推荐
平安的平安2 小时前
Python 实现 AI 图像生成:调用 Stable Diffusion API 完整教程
人工智能·python·stable diffusion
_下雨天.2 小时前
Flask 框架
后端·python·flask
卤炖阑尾炎2 小时前
Flask 框架实战全解:从入门到精通
后端·python·flask
tang777892 小时前
小红书平台用什么代理IP?数据采集IP封禁解决方法
数据库·爬虫·python·网络协议·ip
无籽西瓜a2 小时前
【西瓜带你学设计模式 | 第十五期 - 策略模式】策略模式 —— 算法封装与动态替换实现、优缺点与适用场景
java·后端·设计模式·软件工程·策略模式
Leinwin2 小时前
GitHub Copilot CLI现已支持连接本地Ollama/vLLM模型(附配置指南)
后端·python·flask
Word码2 小时前
接口自动化测试实战项目
软件测试·python·功能测试·集成测试·实战项目
孙同学20202 小时前
如何将 JSON 数据转换为 Excel 工作表
python·json·excel
珍朱(珠)奶茶2 小时前
Spring Boot3整合FreeMark、itextpdf 5/7 实现pdf文件导出及注意问题
java·spring boot·后端·pdf·itextpdf