初识 Flask 框架

发布于:2025-06-15 ⋅ 阅读:(18) ⋅ 点赞:(0)

1、Flask 框架概述

Flask 是 Python 生态中轻量级 Web 微框架,以极简设计、高度灵活为核心特色,专注让开发者高效构建 Web 应用,同时保留拓展自由度。它依赖两大核心 Python 库支撑基础能力:

依赖库名称 Werkzeug Jinja2
角色定位 Flask 的 “底层引擎” Flask 的 “模板渲染中枢”
核心功能 1. 实现 WSGI 规范,处理 HTTP 请求 / 响应全流程
2. 提供路由匹配机制,关联 URL 与视图函数
3. 管理会话、Cookie、请求上下文等基础组件
1. 在 HTML 中嵌入 Python 语法(变量、循环、条件等)
2. 动态渲染数据生成 HTML 页面
3. 支持模板继承、过滤器等高级特性
技术价值 1. 屏蔽底层 HTTP 通信复杂性,让开发者聚焦业务逻辑
2. 提供 URL 规则系统,实现 RESTful API 设计
3. 作为 Web 服务器与应用间的 “翻译官”,确保跨平台兼容性
1. 分离后端逻辑与前端展示,提升代码可维护性
2. 通过模板复用减少代码冗余
3. 支持安全的内容转义,防止 XSS 攻击
典型应用场景 1. 构建自定义中间件处理请求预处理
2. 实现非标准 HTTP 协议扩展
3. 开发测试工具模拟 HTTP 请求
1. 生成带动态数据的 HTML 页面
2. 构建邮件模板系统
3. 实现网站多主题切换功能
拓展能力 可与 Flask 插件组合使用,如 Flask - RESTful 增强 API 功能 支持自定义过滤器和全局函数,扩展模板语法能力

设计理念与适用场景
Flask 主打 “轻量起步,按需拓展”—— 核心仅聚焦基础 Web 开发流程,若开发简单工具(如内部数据看板)、小型 API 服务,直接用核心功能即可快速落地;如需用户认证、数据库 ORM、文件上传等复杂能力,可通过 Flask 生态中丰富的 ** 拓展库(如 Flask - Login、Flask - SQLAlchemy )** 灵活补充,适配从原型验证到中大型项目的多样需求 。这种 “微而不弱” 的特性,让它成为开发者快速试错、定制化 Web 开发的优选框

1.1、安装flask模块

pip3 install flask

1.2、创建一个Flask应用

vim aaa.py
# 从 flask 库中导入 Flask 类,用于创建 Flask 应用实例
from flask import Flask  

# 创建 Flask 应用实例,__name__ 是 Python 内置变量,
# 表示当前模块的名称,Flask 会根据它确定应用的根路径等
app = Flask(__name__)  

# 使用 app.route 装饰器,定义根路径('/')对应的视图函数
# 当用户访问网站根目录时,会执行下面的 aaa 函数
@app.route('/')  
def aaa():
    # 视图函数返回的内容,会作为响应返回给客户端,这里返回简单的字符串 'hello!'
    return 'hello!'  

# Python 的常见写法,判断当前脚本是否作为主程序运行
if __name__ == '__main__':  
    # 运行 Flask 应用,设置 host 为 '0.0.0.0' 表示允许外部所有IP访问,
    # port 为 5000 是应用监听的端口,debug=True 开启调试模式,
    # 调试模式下代码修改后会自动重启,且报错时会显示详细的调试信息
    app.run(host='0.0.0.0', port=5000, debug=True)  

1.3、运行测试

#关闭防火墙
systemctl stop firewalld

#运行应用
python3 aaa.py

2、Flask路由与视图函数

Flask 里,路由系统是很核心的部分 。简单说,就是把用户在浏览器里访问的网址(URL),和我们写的 Python 函数(视图函数)对应起来 。 咋实现的呢?Flask 用 `@app.route()` 这个装饰器来搞。你给这个装饰器里填个网址规则,比如 `@app.route('/greet')` ,然后下面写个函数,这个函数就是视图函数,它的活儿就是处理用户访问这个网址时的请求,最后返回个响应,像返回网页内容、一串文字啥的,让用户能在浏览器看到结果 。

2.1、动态路由

动态路由使用 <变量名> 语法在 URL 路径中定义变量。这些变量会被捕获并作为参数传递给路由函数

# 使用 @app.route 装饰器定义路由规则,
# '/greet/<name>' 表示该路由可以匹配类似 /greet/xxx 的 URL,
# 其中 <name> 是动态路径参数,会将 URL 中对应位置的值传递给视图函数的 name 参数
@app.route('/greet/<name>')  
def greet(name):
    # 视图函数,接收动态参数 name
    # 使用 f-string 格式化字符串,把传入的 name 值拼接到返回内容里,
    # 最终返回类似 "Hello, 传入的名称" 这样的字符串给客户端
    return f'Hello, {name}!'

2.2、支持HTTP的多种获取方式

# 使用 @app.route 装饰器定义路由,这里路由路径是 '/submit' 
# methods 参数指定该路由支持的 HTTP 请求方法,
# 这里同时允许 GET 和 POST 请求访问该路由
@app.route('submit', methods=['GET', 'POST'])  
def submit():
    # 定义视图函数 submit,当客户端访问 '/submit' 路径(且请求方法符合要求)时,
    # 这个函数会被执行,返回字符串 '200 OK!' 作为响应内容给客户端
    return '200 OK!'

2.3、使用 Jinja2 模板渲染 HTML

        Flask 结合 Jinja2 模板引擎来动态生成 HTML 页面。你可以将 HTML 文件与 Python 代码分离,保持应用结构清晰。在 Flask 中,模板文件默认存放在 templates 文件夹中。

创建默认的模板目录:

mkdir templates

在目录下创建index.html模板文件:

<!-- 定义 HTML 文档的开始 -->
<html>
    <!-- head 部分,用于设置页面的元信息、标题等,不会直接显示在页面主体内容里 -->
    <head>
        <!-- meta 标签,指定页面内容的字符编码为 UTF-8,确保中文等字符正确显示 -->
        <meta charset="UTF-8">
        <!-- title 标签,设置浏览器标签栏显示的标题文本 -->
        <title>你好zhangsan!</title>
    </head>

    <!-- body 部分,页面实际显示的内容区域 -->
    <body>
        <!-- h1 是一级标题标签,这里使用了 Flask 模板引擎(Jinja2)的变量语法 {{ name }},
             意味着渲染模板时,会把后端传递的 name 变量值替换到这里显示,实现动态内容展示 -->
        <h1>hello,{{ name }}</h1>
    </body>
</html>

创建脚本文件:

# 从 Flask 框架的核心模块中导入 Flask 类,用于创建 Flask 应用实例
from flask import Flask  
# 从 Flask 框架中导入 render_template 函数,用于渲染 HTML 模板文件
from flask import render_template  

# 创建 Flask 应用实例,__name__ 是 Python 内置变量,
# 它的值是当前模块的名称,Flask 会根据这个值来确定应用的根路径,
# 从而找到模板文件、静态文件等资源的位置
app = Flask(__name__)  

# 使用 @app.route 装饰器为 '/greet/<name>' 路径注册视图函数。
# 这里的 <name> 是动态路由参数,会将 URL 中对应位置的值传递给视图函数的 name 参数
@app.route('/greet/<name>')  
def greet(name):
    # 调用 render_template 函数,渲染名为 'index.html' 的模板文件。
    # 第二个参数 name=name 是将视图函数接收到的 name 参数传递给模板,
    # 这样在模板中就可以使用 {{ name }} 来获取并显示这个值
    return render_template('index.html', name=name)  

# Python 的常见写法,判断当前脚本是否作为主程序运行。
# 当脚本直接被运行时(而不是被其他模块导入时),__name__ 的值会是 '__main__'
if __name__ == '__main__':  
    # 启动 Flask 应用。设置 host='0.0.0.0' 表示允许外部所有 IP 访问该应用;
    # port=5000 指定应用监听的端口为 5000;debug=True 开启调试模式,
    # 在调试模式下,代码修改后应用会自动重启,并且遇到错误时会显示详细的调试信息,方便开发调试
    app.run(host='0.0.0.0', port=5000, debug=True)  

访问测试:

2.4、继承

        Flask 支持模板继承和块(Block)功能,这对于构建复杂页面非常有用。你可以在基础模板中定义通用的布局结构,在子模板中覆盖特定的部分。

创建父模板:

cd /root/templates && mkdir base.html
<html>
<head>
    <!-- 设置网页字符编码为 UTF-8,确保能正确显示中文等多语言字符 -->
    <meta charset="UTF-8">
    <!-- 
        定义标题的模板块(title block),
        子模板可通过继承重写该块来自定义页面标题,
        这里默认标题内容是“欢迎来到我的站点!” 
    -->
    <title>{% block title %}欢迎来到我的站点!{% endblock %}</title>
</head>
<body>
    <!-- 页面头部区域,一般放置站点标识、导航等内容 -->
    <header>
        <!-- 页面头部的一级标题,显示“喜羊羊与灰太狼” -->
        <h1>喜羊羊与灰太狼</h1>
    </header>

    <!-- 中间内容容器,子模板可通过填充 content 块,
         向这里插入具体页面内容,实现模板继承与内容扩展 -->
    <div>
        {% block content %}{% endblock %}
    </div>

    <!-- 页面底部区域,常放置版权信息、联系方式等 -->
    <footer>
        <!-- 显示版权信息,包含日期“2025-06-13”和站点说明“我的站点!” -->
        <p>&copy; 2025-06-13 我的站点!</p>
    </footer>
</body>
</html>

创建子模板:

vim index.html
{# 继承 base.html 模板,让当前子模板拥有父模板的整体结构,后续可填充/覆盖父模板的区块 #}
{% extends 'base.html' %}

{# 定义 title 区块,用于覆盖父模板中同名的 title 区块,设置页面标题为 Home #}
{% block title %}Home{% endblock %}

{# 定义 content 区块,用于填充父模板中预留的 content 区块 #}
{% block content %}
    {# 在 content 区块里添加具体内容,这里是一个二级标题“欢迎来到战场!” #}
    <h2>欢迎来到战场!</h2>
{# 结束 content 区块的定义 #}
{% endblock %}

访问测试:

from flask import Flask

from flask import render_template

app = Flask(__name__)



# 使用 @app.route 装饰器,为 Flask 应用定义路由规则,这里指定根路径(即网站首页,访问域名/时触发)
@app.route('/')  
# 定义视图函数 aaa,当访问上述指定路由(根路径)时,这个函数会被执行
def aaa():  
    # 调用 render_template 函数,渲染名为 index.html 的模板文件并返回给客户端
    # 作用是将模板里的内容(结合可能传入的数据,这里没传额外数据)转换为 HTML 响应返回
    return render_template('index.html')




if __name__ == '__main__':
    app.run(host='0.0.0.0',port=5000,debug=True)







  

3、Flask 表单处理与用户输入

        Flask 可以通过表单来获取用户输入,常见的做法是结合 FlaskK-WTE 扩展来简化表单处理和验证。
Flask-WTF 为 Flask 提供了一个表单类,你可以在表单类中定义字段和验证规则。

3.1、安装Flask-WTF

pip3 install flask-wtf

3.2、制作一个表单

vim biaodan.py
# 从 Flask 框架中导入 Flask 类(用于创建应用实例)、render_template 函数(渲染模板)、request 对象(处理请求)
from flask import Flask, render_template, request  
# 从 flask_wtf 库中导入 FlaskForm 类,用于创建表单类
from flask_wtf import FlaskForm  
# 从 wtforms 库中导入 StringField 类,用于创建字符串输入框表单字段
from wtforms import StringField  
# 从 wtforms.validators 中导入 DataRequired 验证器,用于要求字段必须填写内容
from wtforms.validators import DataRequired  

# 创建 Flask 应用实例,__name__ 会根据当前模块名称动态赋值,帮助 Flask 找到模板和静态文件等资源
app = Flask(__name__)  
# 设置 Flask 应用的密钥,用于会话安全、表单 CSRF 保护等,这里简单设为's3cr3t'(实际应用应设更复杂安全的密钥)
app.secret_key ='s3cr3t'  

# 定义表单类 NameForm,继承自 FlaskForm,用于创建包含特定字段的表单
class NameForm(FlaskForm):  
    # 创建一个字符串输入框字段,名称为'name',在页面上显示的标签是'Name',并且要求该字段必须填写(通过 DataRequired 验证器)
    name = StringField('Name', validators=[DataRequired()])  

# 定义路由装饰器,将根路径'/'与视图函数 index 关联,允许处理 GET 和 POST 请求
@app.route('/', methods=['GET', 'POST'])  
def index():  
    # 创建 NameForm 表单实例,用于后续处理用户提交或展示表单
    form = NameForm()  
    # 检查表单是否通过验证且是通过提交(POST)方式触发,validate_on_submit 会先检查请求方法是否是 POST,再验证表单字段
    if form.validate_on_submit():  
        # 如果验证通过,获取表单中 name 字段用户输入的数据,拼接成问候语并返回
        return f'Hello, {form.name.data}!'  
    # 如果不是通过提交触发(比如初始访问是 GET 请求),渲染 index.html 模板,并把表单实例传给模板,方便在页面上显示表单
    return render_template('index.html', form=form)  

# Python 脚本入口判断,当脚本被直接运行时执行下面代码
if __name__ == '__main__':  
    # 原本的启动方式,调试模式开启(调试模式下代码改动会自动重启应用,且报错信息更详细,不过仅适合开发环境),这里被注释了
    # app.run(debug=True)  
    # 实际使用的启动方式,设置主机为 '0.0.0.0'(允许外部设备访问该应用,比如同一局域网内的其他机器),端口为 5000,开启调试模式
    app.run(host='0.0.0.0', port=5000, debug=True)  

index.html模板:

vim index.html
<!-- 定义 HTML 文档,语言为英文("en" 表示 English ) -->
<html lang="en">
<head>
    <!-- 设置网页的字符编码为 UTF-8,确保能正确显示各种字符,避免乱码 -->
    <meta charset="UTF-8">
    <!-- 设置网页标题,在浏览器标签上显示为 "Flask Form" -->
    <title>Flask Form</title>
</head>
<body>
    <!-- 一级标题,提示用户输入姓名 -->
    <h1>Enter your name:</h1>
    <!-- 定义表单,提交数据时使用 POST 方法,和 Flask 后端路由 @app.route('/', methods=['GET', 'POST']) 对应,用于将用户输入的数据提交到后端 -->
    <form method="POST">
        <!-- 渲染 CSRF 令牌,这是 flask_wtf 提供的安全机制,用于防止跨站请求伪造攻击。后端通过设置 secret_key 配合,表单必须包含这个令牌,后端才会认可表单提交 -->
        {{ form.csrf_token }}
        <!-- 标签,关联下方的 name 输入框,点击标签也能聚焦到输入框,提升用户体验,"for" 属性值和表单字段的 id 对应(由 Flask-WTF 自动处理) -->
        <label for="name">Name:</label>
        <!-- 渲染 NameForm 中的 name 字符串输入框字段,会生成对应的 HTML input 元素,用户在这里输入姓名。<br><br> 是换行符,让输入框和按钮之间空出两行间距 -->
        {{ form.name() }}<br><br>
        <!-- 提交按钮,用户点击后触发表单的提交操作,将数据发送到后端 Flask 应用的对应路由进行处理 -->
        <button type="submit">Submit</button>
    </form>

    <!-- Jinja2 模板的条件判断语法,检查表单中 name 字段是否有用户提交的数据(即是否经过了有效提交且通过验证) -->
    {% if form.name.data %}
        <!-- 如果有提交的姓名数据,就用二级标题显示问候语,展示用户输入的姓名,实现前后端数据交互后的反馈 -->
        <h2>Hello, {{ form.name.data }}!</h2>
    <!-- 条件判断结束的语法标记 -->
    {% endif %}
</body>
</html>

验证:

4、项目

路径 类型 作用说明
/my_flask_app 目录 项目根目录,包裹整个 Flask 应用的所有文件,是项目的容器。
/my_flask_app/app 目录 应用核心目录,集中存放应用的主要逻辑(路由、表单、初始化等),便于模块化管理。
/templates 目录 存放 HTML 模板文件,Flask 会从这里读取模板,结合视图函数渲染动态页面。
index.html 文件 示例 HTML 模板,实际项目中会有更多页面模板,用于展示页面内容、嵌入 Jinja2 语法。
/static 目录 静态资源存储地,浏览器可直接访问这里的文件(如 CSS 美化样式、JS 交互脚本 )。
/css 目录 专门存放 CSS 样式文件,管理页面视觉效果(布局、颜色、字体等 )。
/js 目录 存放 JavaScript 文件,实现前端交互逻辑(如按钮点击、数据异步请求 )。
__init__.py 文件 标记 app 为 Python 包,在此创建 Flask 应用实例、配置扩展(如数据库、密钥 )。
routes.py 文件 定义 URL 路由规则和对应的视图函数,决定用户访问不同地址时执行的逻辑与返回内容。
forms.py 文件 若使用 Flask-WTF 等表单扩展,在此定义表单类(包含字段、验证规则 ),方便前后端表单交互。
run.py 文件 应用启动入口,编写代码运行 Flask 开发服务器,让应用可被外部访问调试。

4.1、栗子:

项目结构:

路径 说明
/simple_blog 项目的根目录,作为整个博客应用的容器,包裹所有相关文件
/app 应用核心目录,存放博客应用的主要代码逻辑,实现功能封装与模块化管理
/templates 模板目录,用于存放 HTML 模板文件(如 index.html ),借助 Flask 等框架渲染动态页面,分离前端展示与后端逻辑
index.html 示例 HTML 模板文件,可作为博客首页等页面的基础,后续可扩展布局、内容展示等
app.py 核心代码文件,通常用于编写 Flask 应用的初始化、路由定义、业务逻辑等,是应用的 “大脑”,控制请求响应流程

app.py:
vim app.py
# 从 flask 框架中导入 Flask 类(用于创建应用实例)、render_template 函数(用于渲染模板)、request 对象(用于处理请求数据)
from flask import Flask, render_template, request  

# 创建 Flask 应用实例,__name__ 代表当前 Python 模块的名称,Flask 会根据它确定应用相关资源(如模板、静态文件)的路径
app = Flask(__name__)  

# 定义一个列表,用于存储所有的文章数据,每个元素是包含 'title'(标题)和 'content'(内容)的字典
posts = []  

# 定义路由装饰器,将根路径('/')与视图函数 index 绑定,同时允许处理 GET 和 POST 两种请求方法
@app.route('/', methods=['GET', 'POST'])  
def index():
    # 判断请求方法是否为 POST,如果是,说明是用户提交表单数据
    if request.method == 'POST':  
        # 从请求的表单数据中获取标题,键为 'title',对应前端表单里的名称
        title = request.form['title']  
        # 从请求的表单数据中获取文章内容,键为 'content',对应前端表单里的名称
        content = request.form['content']  
        # 将获取到的标题和内容整理成字典,添加到 posts 列表中,实现文章数据的存储
        posts.append({'title': title, 'content': content})  
    # 渲染名为 'index.html' 的模板文件,把 posts 列表传递给模板,这样模板中就能使用该数据展示文章,最后返回渲染后的结果给客户端
    return render_template('index.html', posts=posts)  

# 判断当前脚本是否是作为主程序运行(而不是被其他模块导入)
if __name__ == '__main__':  
    # 启动 Flask 应用,设置 host 为 '0.0.0.0' 表示允许外部所有 IP 访问,端口为 5000,debug=True 开启调试模式,代码修改后会自动重启,且能显示错误详情
    app.run(host='0.0.0.0', port=5000, debug=True)  

index.html:
vim index.html
<html lang="en"> <!-- 定义 HTML 文档的语言为英语 -->
<head>
    <meta charset="UTF-8"> <!-- 设置字符编码为 UTF-8,确保正确显示各种字符 -->
    <title>Simple Blog</title> <!-- 设置网页标题,会在浏览器标签栏显示 -->
</head>
<body>
    <h1>Welcome to the Blog!</h1> <!-- 一级标题,显示博客欢迎语 -->

    <h2>Submit a Post</h2> <!-- 二级标题,标识提交文章的区域 -->
    <form method="POST"> <!-- 定义一个 POST 方法的表单,用于提交文章数据 -->
        <label for="title">Title:</label> <!-- 关联“title”输入框的标签,说明要填写标题 -->
        <input type="text" id="title" name="title" required><br><br> 
        <!-- 
            文本类型输入框,id 和 name 都为“title”,required 表示该字段为必填项 
            填写的标题内容会随表单提交,<br> 用于换行 
        -->

        <label for="content">Content:</label> <!-- 关联“content”文本域的标签,说明要填写内容 -->
        <textarea id="content" name="content" required></textarea><br><br> 
        <!-- 
            多行文本域,id 和 name 都为“content”,required 表示必填 
            用于填写文章具体内容,填写的内容会随表单提交,<br> 用于换行 
        -->

        <button type="submit">Submit</button> <!-- 提交按钮,点击后提交表单数据 -->
    </form>

    <h2>Posts:</h2> <!-- 二级标题,标识展示文章列表的区域 -->
    <ul> <!-- 无序列表,用于包裹文章列表项 -->
        {% for post in posts %} <!-- Jinja2 模板的 for 循环,遍历名为 posts 的列表数据 -->
            <li> <!-- 列表项,每个文章对应一个列表项 -->
                <h3>{{ post.title }}</h3> <!-- 展示文章的标题,从 post 对象的 title 属性获取内容 -->
                <p>{{ post.content }}</p> <!-- 展示文章的内容,从 post 对象的 content 属性获取内容 -->
            </li>
        {% endfor %} <!-- 结束 for 循环 -->
    </ul>
</body>
</html>
验证:


网站公告

今日签到

点亮在社区的每一天
去签到