Flask入门:Python Web框架快速上手 – wiki基地


Flask 入门:Python Web 框架快速上手指南

欢迎来到 Python Web 开发的世界!如果您正在寻找一个轻量级、灵活且易于上手的 Web 框架,那么 Flask 绝对是您的理想选择。与一些大型的“全栈”框架(如 Django)不同,Flask 被称为“微框架”,因为它只提供 Web 开发的核心功能,而将数据库、认证、表单验证等功能交给扩展来处理。这种设计理念使得 Flask 更加灵活,开发者可以根据自己的需求自由选择和组合工具。

本文将带您从零开始,一步步深入 Flask 的世界,学习如何搭建开发环境、构建第一个应用、处理请求与响应、使用模板、集成静态文件、处理表单数据,并初步了解数据存储的概念。无论您是刚刚接触 Web 开发的 Python 爱好者,还是希望尝试一个新框架的经验丰富的开发者,本文都将为您提供扎实的入门基础。

文章结构:

  1. Flask 简介: 什么是 Flask?为什么选择 Flask?
  2. 准备工作: 安装 Python、pip 和创建虚拟环境。
  3. 安装 Flask: 使用 pip 安装 Flask。
  4. 你的第一个 Flask 应用: 编写并运行一个简单的 “Hello, World!” 应用。
  5. 理解核心概念: 应用实例、路由、视图函数。
  6. 处理不同 URL 和 HTTP 方法: 创建多个路由,处理 GET 和 POST 请求。
  7. 动态 URL (URL 变量): 如何从 URL 中捕获变量。
  8. 使用模板: 告别硬编码 HTML,引入 Jinja2 模板引擎。
    • 创建模板文件
    • 渲染模板并传递数据
    • 模板继承简介
  9. 静态文件: 如何在 Flask 应用中提供 CSS、JavaScript 和图片。
  10. 处理表单数据: 从用户提交的表单中获取数据。
    • 创建 HTML 表单
    • 在 Flask 中接收和处理表单数据
    • 重定向与 url_for
  11. 数据存储简介: 为什么需要数据库?Flask 如何与数据库集成(概念性介绍)。
  12. 会话 (Sessions): 在请求之间存储用户特定信息。
  13. 错误处理: 定制 404 等错误页面。
  14. 组织大型应用 (蓝图简介): 如何使用蓝图使应用结构更清晰。
  15. 下一步: 部署、测试、更高级功能和常用扩展。
  16. 总结: 回顾所学,鼓励实践。

好,让我们开始这段 Flask 学习之旅吧!


1. Flask 简介:什么是 Flask?为什么选择 Flask?

什么是 Flask?

Flask 是一个使用 Python 编写的轻量级 Web 服务器网关接口(WSGI)Web 应用框架。它基于 Werkzeug WSGI 工具集和 Jinja2 模板引擎。Flask 的目标是保持核心功能的简洁和灵活,通过扩展来增加额外功能。这使得开发者可以根据项目需求选择合适的工具,而不是被框架强制使用特定的库或方法。

为什么选择 Flask?

  1. 轻量级和简洁: Flask 的核心非常小巧,学习曲线相对平缓。您可以在短时间内理解其基本工作原理。
  2. 灵活和可扩展: Flask 不做过多限制,您可以自由选择数据库、模板引擎(尽管默认是 Jinja2)、ORM(对象关系映射)工具等。社区提供了大量的 Flask 扩展,可以轻松集成各种功能,如用户认证、数据库操作、表单处理、缓存等。
  3. 易于上手: 对于有 Python 基础的开发者来说,学习 Flask 非常容易。它的 API 设计直观,文档清晰。
  4. 非常适合小型到中型应用: Flask 在构建简单的 Web 服务、API 或者原型开发时表现出色。当然,通过良好的架构设计和合理使用扩展,Flask 也能用于构建大型复杂应用。
  5. 活跃的社区: Flask 拥有一个活跃的开发者社区,您可以轻松找到教程、文档和寻求帮助。

如果您追求快速启动、高度定制化,或者您的项目规模适中,不希望被框架的“全家桶”所束缚,那么 Flask 是一个非常好的选择。

2. 准备工作:安装 Python、pip 和创建虚拟环境

在开始之前,请确保您的系统已经安装了 Python 和 pip(Python 的包管理器)。通常安装 Python 时会自动安装 pip。

  • 安装 Python: 访问 python.org 下载并安装最新版本的 Python 3。在安装过程中,请确保勾选“Add Python to PATH”(将 Python 添加到系统路径)。
  • 验证安装: 打开终端或命令提示符,输入以下命令验证 Python 和 pip 是否安装成功:
    bash
    python --version
    pip --version

    如果显示版本号,则说明安装成功。

创建和使用虚拟环境 (Virtual Environments)

强烈建议在进行任何 Python 项目开发时使用虚拟环境。虚拟环境可以为您的项目创建一个独立的 Python 环境,所有安装的库都将在这个环境中,不会影响系统全局的 Python 安装或其他项目。这有助于避免不同项目之间库版本冲突的问题。

  1. 创建虚拟环境: 打开终端或命令提示符,切换到您希望创建项目的目录。然后执行以下命令创建一个名为 venv 的虚拟环境(名称可以自定义):

    • 在 macOS/Linux 上:
      bash
      python3 -m venv venv
    • 在 Windows 上:
      bash
      python -m venv venv

      这会在当前目录下创建一个名为 venv 的文件夹,其中包含独立的 Python 解释器和 pip。
  2. 激活虚拟环境: 在开始项目开发或安装库之前,需要激活虚拟环境。

    • 在 macOS/Linux 上:
      bash
      source venv/bin/activate
    • 在 Windows 命令提示符 (cmd) 上:
      bash
      venv\Scripts\activate
    • 在 Windows PowerShell 上:
      powershell
      .\venv\Scripts\Activate.ps1

      激活成功后,您会看到终端提示符前面多了一个 (venv) 字样,表示您当前正处于 venv 虚拟环境中。
  3. 退出虚拟环境: 当您完成项目开发或需要切换到其他环境时,可以简单地输入 deactivate 命令来退出当前虚拟环境。

请注意: 在激活虚拟环境后,使用 pip install 命令安装的任何库都将只安装到当前激活的虚拟环境中。

3. 安装 Flask

虚拟环境激活后,安装 Flask 就非常简单了。使用 pip 执行以下命令:

bash
pip install Flask

Pip 会自动下载并安装 Flask 及其依赖项(主要是 Werkzeug 和 Jinja2)。安装完成后,您可以输入 pip list 查看当前虚拟环境中安装的所有库,应该能看到 Flask、Werkzeug、Jinja2、MarkupSafe 和 ItsDangerous。

至此,您的开发环境已经准备就绪,可以开始编写第一个 Flask 应用了!

4. 你的第一个 Flask 应用:”Hello, World!”

按照惯例,我们的第一个 Web 应用将是一个经典的 “Hello, World!”。

创建一个名为 app.py 的 Python 文件,并将以下代码复制进去:

“`python

app.py

from flask import Flask

创建一个 Flask 应用实例

name 是一个特殊的 Python 变量,它的值取决于运行哪个模块。

如果它是直接运行的模块,name 的值是 ‘main‘。

Flask 需要知道在哪里查找资源,name 参数告诉 Flask 应用的根目录。

app = Flask(name)

使用装饰器 @app.route() 定义一个 URL 路由

当用户访问应用程序的根 URL (‘/’) 时,将执行下面的 home() 函数

@app.route(‘/’)
def home():
“””处理根 URL(‘/’)的请求,返回一个简单的字符串响应.”””
return ‘Hello, World! Welcome to my first Flask app!’

确保此脚本直接运行时才启动开发服务器

if name == ‘main‘: 是 Python 的标准用法,

保证这段代码只在直接运行 app.py 时执行,而不是被其他文件导入时执行。

debug=True 开启调试模式,开发过程中非常有用,代码修改后服务器会自动重载,

并且在发生错误时提供详细的错误信息。但在生产环境中必须关闭调试模式!

if name == ‘main‘:
app.run(debug=True)
“`

代码解释:

  • from flask import Flask: 从 flask 库中导入 Flask 类。
  • app = Flask(__name__): 创建 Flask 应用程序的实例。__name__ 是必需的,它可以帮助 Flask 确定应用程序的根目录,以便找到资源文件(如模板和静态文件)。
  • @app.route('/'): 这是一个装饰器,它将下面的函数 home() 绑定到 URL /。当用户在浏览器中访问应用程序的根地址(例如 http://127.0.0.1:5000/)时,Flask 会执行 home() 函数。
  • def home():: 这是一个视图函数。当对应的 URL 被访问时,Flask 会调用这个函数。函数返回的值就是发送给用户的响应。在这里,它返回一个简单的字符串。
  • if __name__ == '__main__':: 这是一个标准的 Python 惯用法,确保 app.run() 只在直接运行 app.py 这个文件时执行。
  • app.run(debug=True): 启动 Flask 的开发服务器。debug=True 开启了调试模式,这在开发过程中非常方便,它可以让服务器在代码修改后自动重载,并在发生错误时提供详细的错误信息。请记住,在生产环境中永远不要开启调试模式,因为它可能会暴露敏感信息。

运行应用程序:

  1. 确保您已经激活了之前创建的虚拟环境。
  2. 在终端或命令提示符中,切换到存放 app.py 文件的目录。
  3. 执行以下命令:
    bash
    python app.py

您会看到类似以下的输出:

* Serving Flask app 'app' (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: XXX-XXX-XXX

这表示 Flask 开发服务器已经在本地启动,监听端口 5000。

现在,打开您的浏览器,访问 http://127.0.0.1:5000/。您应该能看到页面上显示 “Hello, World! Welcome to my first Flask app!”。

恭喜您!您已经成功运行了您的第一个 Flask 应用!

5. 理解核心概念:应用实例、路由、视图函数

在上面的 “Hello, World!” 例子中,我们已经接触了 Flask 的几个核心概念:

  • 应用实例 (app = Flask(__name__)): 这是整个 Flask 应用的中心。您会在这个实例上配置应用、注册路由、处理请求等。它是您创建的每个 Flask 应用的起点。
  • 路由 (@app.route('/')): 路由是将特定的 URL 模式映射到处理该 URL 的函数的过程。在 Flask 中,通常使用 @app.route() 装饰器来定义路由。当 Flask 接收到针对某个 URL 的请求时,它会查找与之匹配的路由,并调用相应的视图函数。
  • 视图函数 (def home():): 视图函数是用来处理特定路由请求的 Python 函数。它的职责是处理请求逻辑(如读取数据、处理表单等)并返回一个响应,这个响应通常是 HTML 页面、JSON 数据或简单的字符串。

6. 处理不同 URL 和 HTTP 方法

一个真实的 Web 应用通常需要处理多个不同的 URL。我们可以在 app.py 文件中添加更多路由和视图函数。

修改 app.py 文件如下:

“`python
from flask import Flask

app = Flask(name)

@app.route(‘/’)
def home():
return ‘Welcome to the Home Page!’

@app.route(‘/about’)
def about():
return ‘This is the About page of my Flask app.’

@app.route(‘/contact’)
def contact():
return ‘Contact us at [email protected]

处理特定的 HTTP 方法

默认路由只接受 GET 请求

可以通过 methods 参数指定接受的 HTTP 方法

@app.route(‘/submit’, methods=[‘GET’, ‘POST’])
def submit():
if request.method == ‘POST’:
# 处理 POST 请求的逻辑 (稍后在表单处理中详细介绍)
return ‘Received a POST request’
else:
# 处理 GET 请求的逻辑
return ‘Send a POST request to this URL’

导入 request 对象以便访问请求数据

from flask import request

… (前面的代码) …

@app.route(‘/submit’, methods=[‘GET’, ‘POST’])
def submit():
if request.method == ‘POST’:
# 在处理表单时我们会使用 request.form 来获取 POST 数据
# 现在只是简单返回一个确认信息
return ‘Received a POST request for submission.’
else:
return ‘This page is for submitting data via POST.’

if name == ‘main‘:
app.run(debug=True)
“`

重新运行 python app.py。现在您可以访问:

  • http://127.0.0.1:5000/
  • http://127.0.0.1:5000/about
  • http://127.0.0.1:5000/contact
  • http://127.0.0.1:5000/submit (使用 GET 请求访问会显示 “This page is for submitting data via POST.”)

HTTP 方法:

Web 请求使用不同的 HTTP 方法,最常见的是 GET 和 POST。

  • GET: 用于从服务器获取数据。例如,当您在浏览器中直接输入 URL 访问一个页面时,使用的是 GET 请求。
  • POST: 通常用于向服务器提交数据,例如提交表单。

默认情况下,@app.route() 装饰器只响应 GET 请求。通过设置 methods=['GET', 'POST'],您可以让同一个视图函数处理不同类型的请求。在函数内部,您可以使用 request.method 来判断当前请求是 GET 还是 POST,并执行相应的逻辑。request 对象是 Flask 提供的一个全局对象,用于访问当前请求的所有信息(如方法、表单数据、URL 参数等)。

7. 动态 URL (URL 变量)

很多时候,URL 中会包含一些变量,例如用户 ID、文章 ID 等。Flask 允许您在路由规则中定义这样的变量。

修改 app.py 文件,添加一个处理用户信息的路由:

“`python

… (前面的代码) …

@app.route(‘/user/‘)
def show_user_profile(username):
“””根据用户名显示用户资料页.”””
# username 变量会从 URL 中捕获并作为参数传递给函数
return f’User Profile: {username}’

@app.route(‘/post/‘)
def show_post(post_id):
“””根据文章 ID 显示文章详情页.”””
# 指定 post_id 必须是一个整数
# Flask 会自动将其转换为 int 类型并传递给函数
return f’Post ID: {post_id}’

… (if name == ‘main‘: …)

“`

重新运行 python app.py。现在您可以访问:

  • http://127.0.0.1:5000/user/Alice -> 显示 “User Profile: Alice”
  • http://127.0.0.1:5000/user/Bob -> 显示 “User Profile: Bob”
  • http://127.0.0.1:5000/post/1 -> 显示 “Post ID: 1”
  • http://127.0.0.1:5000/post/123 -> 显示 “Post ID: 123”
  • http://127.0.0.1:5000/post/abc -> 会返回 404 Not Found 错误,因为 ‘abc’ 不是整数,与 <int:post_id> 不匹配。

URL 变量和转换器:

在路由规则中,使用 <variable_name> 语法来定义 URL 变量。Flask 会捕获 URL 中对应位置的值,并将其作为关键字参数传递给视图函数。

您还可以指定变量的类型,称为转换器 (Converters)。常用的转换器包括:

  • <string:variable> (默认): 接受任何不包含斜杠的字符串。
  • <int:variable>: 接受整数。
  • <float:variable>: 接受浮点数。
  • <path:variable>: 接受包含斜杠的字符串,通常用于匹配文件路径。
  • <uuid:variable>: 接受 UUID 字符串。

使用转换器可以帮助 Flask 进行基本的 URL 验证,确保捕获到的变量符合预期类型。

8. 使用模板

直接在视图函数中返回 HTML 字符串对于简单的应用来说尚可,但对于复杂的页面布局和动态内容,这种方式将变得难以维护。我们需要将页面的结构(HTML)与数据和逻辑(Python 视图函数)分离开来。这就是模板引擎的作用。

Flask 默认集成了 Jinja2 模板引擎,它非常强大且易于使用。

步骤:

  1. 创建 templates 文件夹: 在与 app.py 同级的目录下创建一个名为 templates 的文件夹。Flask 默认会在这个文件夹中查找模板文件。
  2. 创建模板文件:templates 文件夹中创建一个名为 index.html 的文件。

    “`html

    <!DOCTYPE html>




    {{ title }} {# 使用 {{ }} 语法插入变量 #}

    Hello, {{ name }}!

    {# 变量 name 的值会在这里显示 #}

    Welcome to our Flask application.

    {# Jinja2 控制结构示例 #}
    {% if users %} {# 使用 {% %} 语法执行控制结构 #}
        <h2>Users:</h2>
        <ul>
            {% for user in users %} {# 循环遍历 users 列表 #}
                <li>{{ user }}</li>
            {% endfor %}
        </ul>
    {% else %}
        <p>No users found.</p>
    {% endif %}
    
    <p>Current Year: {{ current_year }}</p> {# 传递数字变量 #}
    



    ``
    在 Jinja2 模板中:
    *
    {{ variable }}用于输出变量的值。
    *
    {% statement %}用于执行控制结构,如if语句、for循环等。
    *
    {# comment #}` 用于添加注释。

  3. 在 Flask 中渲染模板: 修改 app.py,导入 render_template 函数,并修改视图函数以使用模板。

    “`python
    from flask import Flask, render_template # 导入 render_template

    app = Flask(name)

    @app.route(‘/’)
    def index():
    “””渲染首页模板.”””
    # 定义要传递给模板的数据
    page_title = ‘Home Page’
    user_name = ‘Guest’
    user_list = [‘Alice’, ‘Bob’, ‘Charlie’]
    current_year = 2023 # 示例数据

    # 调用 render_template 函数,指定模板文件名和要传递的变量
    # 变量以关键字参数的形式传递,键名即为模板中使用的变量名
    return render_template('index.html',
                           title=page_title,
                           name=user_name,
                           users=user_list,
                           current_year=current_year)
    

    … (其他路由和 if name == ‘main‘: …)

    “`

重新运行 python app.py,访问 http://127.0.0.1:5000/。您将看到由 index.html 模板渲染生成的页面,其中变量 titlenameuserscurrent_year 的值已经被替换。

模板继承简介:

对于大型应用,不同的页面通常会有很多共同的部分(如头部、导航、底部)。模板继承是 Jinja2 的一个强大特性,可以帮助您避免在每个模板文件中重复编写这些共同部分。

  1. 创建一个 base.html 基础模板:
    “`html

    <!DOCTYPE html>




    {% block title %}My Flask App{% endblock %} {# 定义一个名为 title 的块 #}
    {# 可以添加一些公共的 CSS 或 JS 链接 #}

    {% block page_header %}Welcome{% endblock %}

    {# 定义页面标题块 #}

    <main>
        {% block content %}{% endblock %} {# 定义一个名为 content 的块,用于插入具体页面的内容 #}
    </main>
    
    <footer>
        <p>&copy; {{ current_year }} My Flask App</p>
    </footer>
    



    ``{% block block_name %}{% endblock %}` 定义了一个可以被子模板覆盖的区域。

  2. 修改 index.html 和其他模板,使其继承 base.html
    “`html

    {% extends “base.html” %} {# 声明继承 base.html #}

    {% block title %}Home{% endblock %} {# 覆盖 base.html 中的 title 块 #}

    {% block page_header %}Home Page{% endblock %} {# 覆盖 base.html 中的 page_header 块 #}

    {% block content %} {# 覆盖 base.html 中的 content 块 #}

    This is the main content for the home page.

    <h2>Users:</h2>
    <ul>
        {% for user in users %}
            <li>{{ user }}</li>
        {% endfor %}
    </ul>
    

    {% endblock %}
    html

    {% extends “base.html” %}

    {% block title %}About{% endblock %}

    {% block page_header %}About Us{% endblock %}

    {% block content %}

    Learn more about our amazing Flask app.

    {% endblock %}
    “`

  3. app.py 中创建渲染 about.html 的路由(如果需要):
    “`python
    # … (前面的导入和 app 实例) …

    @app.route(‘/’)
    def index():
    # … (传递给 index.html 的变量) …
    user_list = [‘Alice’, ‘Bob’, ‘Charlie’]
    current_year = 2023
    return render_template(‘index.html’,
    title=’Home’, # 可以在这里传递值给 base.html 中的 block
    name=’Guest’,
    users=user_list,
    current_year=current_year)

    @app.route(‘/about’)
    def about():
    current_year = 2023 # 如果 base.html 需要这个变量
    return render_template(‘about.html’, current_year=current_year) # 渲染 about.html

    … (其他路由和 if name == ‘main‘: …)

    ``
    注意:如果
    base.html中的 block 依赖于某个变量(如current_year),那么在渲染继承它的子模板时,也需要将这个变量传递给render_template函数,即使它只在base.html` 中使用。

使用模板继承可以极大地提高代码的复用性和可维护性。

9. 静态文件

Web 应用通常需要提供静态文件,如 CSS 样式表、JavaScript 脚本、图片、字体文件等。Flask 也为此提供了方便的支持。

  1. 创建 static 文件夹: 在与 app.pytemplates 文件夹同级的目录下创建一个名为 static 的文件夹。Flask 默认会在这里查找静态文件。
  2. 创建静态文件:static 文件夹中创建一个子文件夹,例如 css,并在其中创建一个 style.css 文件。

    “`css
    / static/css/style.css /
    body {
    font-family: sans-serif;
    margin: 20px;
    background-color: #f4f4f4;
    }

    h1, h2 {
    color: #333;
    }

    nav a {
    margin-right: 10px;
    text-decoration: none;
    }

    footer {
    margin-top: 20px;
    padding-top: 10px;
    border-top: 1px solid #ccc;
    font-size: 0.9em;
    color: #666;
    }
    “`

  3. 在模板中链接静态文件: 在您的模板文件(例如 base.htmlindex.html<head> 部分)中,使用 url_for() 函数来生成静态文件的 URL。

    html
    <!-- templates/base.html (修改 head 部分) -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}My Flask App{% endblock %}</title>
    {# 使用 url_for 生成静态文件 URL #}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
    </head>
    <body>
    {# ... (body content) ... #}
    </body>
    </html>

url_for() 函数:

url_for() 是 Flask 提供的一个非常实用的函数,用于为指定的视图函数或静态文件生成 URL。它的第一个参数是“端点名称”(Endpoint Name)。

  • 对于视图函数,端点名称通常是视图函数的名称(例如,home 视图函数的端点就是 'home')。url_for('home') 会生成 /。如果您有带有参数的路由,例如 @app.route('/user/<username>') 对应的 show_user_profile 函数,可以使用 url_for('show_user_profile', username='Alice') 来生成 /user/Alice
  • 对于静态文件,端点名称是 'static'url_for('static', filename='css/style.css') 会生成 /static/css/style.css。Flask 开发服务器会自动处理 /static/ 路径下的请求,并将 static 文件夹中的文件作为响应返回。

使用 url_for() 而不是硬编码 URL 有两个好处:
1. 路由规则变化时,链接会自动更新: 如果您修改了 @app.route('/')@app.route('/index'),只需要在 app.py 中修改,模板中的 url_for('index') 仍然会生成正确的 /index URL。
2. 更好地处理 URL 前缀等情况: 在更复杂的部署场景中,应用可能有 URL 前缀,url_for 可以正确地处理这些情况。

重新运行应用,访问首页,您应该能看到页面应用了 style.css 中的样式。

10. 处理表单数据

Web 应用与用户交互最常见的方式之一就是通过表单。用户在表单中输入信息,然后提交到服务器进行处理。

步骤:

  1. 创建包含表单的模板: 创建一个 form.html 模板文件。

    “`html

    {% extends “base.html” %}

    {% block title %}Contact Form{% endblock %}

    {% block page_header %}Contact Us{% endblock %}

    {% block content %}

    Please fill out the form below:

    <form method="POST" action="{{ url_for('submit_form') }}"> {# 表单提交到 submit_form 路由 #}
        <div>
            <label for="name">Name:</label><br>
            <input type="text" id="name" name="name" required>
        </div>
        <br>
        <div>
            <label for="email">Email:</label><br>
            <input type="email" id="email" name="email" required>
        </div>
        <br>
        <div>
            <label for="message">Message:</label><br>
            <textarea id="message" name="message" rows="4" cols="50" required></textarea>
        </div>
        <br>
        <div>
            <button type="submit">Submit</button>
        </div>
    </form>
    

    {% endblock %}
    ``
    *

    : 表单使用 POST 方法提交数据,提交的 URL 由url_for(‘submit_form’)生成,这将对应到我们稍后创建的名为submit_form的路由。
    *
    ,

滚动至顶部