学习 Flask:你的第一个 Web 应用 – wiki基地


学习 Flask:你的第一个 Web 应用

欢迎来到激动人心的 Web 开发世界!如果你是一位 Python 爱好者,并且渴望将你的代码带到互联网上,那么 Flask 是一个绝佳的起点。作为一个轻量级的 Web 服务框架,Flask 以其简洁、灵活的特性赢得了众多开发者的喜爱。它不强制使用任何特定的数据库或模板引擎,这给了你极大的自由度来选择最适合你的工具。

在这篇文章中,我们将一起踏上学习 Flask 的旅程,从零开始构建你的第一个 Web 应用。我们将涵盖环境搭建、核心概念、模板使用、静态文件处理等基础知识,让你快速入门并亲手运行一个简单的 Web 站点。

准备好了吗?让我们开始吧!

1. 准备工作:搭建你的开发环境

在开始编写代码之前,我们需要确保你的开发环境已经准备就绪。

1.1 安装 Python

首先,确保你的系统上已经安装了 Python。推荐使用 Python 3.6 或更高版本。你可以在 Python 官方网站 下载并安装适合你操作系统的版本。安装完成后,打开终端或命令行工具,输入以下命令检查 Python 版本:

“`bash
python –version

或者

python3 –version
“`

如果你看到输出了版本号,说明 Python 已经安装成功。

1.2 创建并激活虚拟环境

在 Python 项目中,强烈推荐使用虚拟环境(Virtual Environment)。虚拟环境可以隔离不同项目所需的库版本,避免相互冲突。

在你的项目目录下(例如,创建一个名为 my-flask-app 的文件夹),打开终端,执行以下命令创建虚拟环境:

“`bash

在 my-flask-app 文件夹内执行

python -m venv venv

或者

python3 -m venv venv
“`

这会在当前目录下创建一个名为 venv 的文件夹,其中包含了独立的 Python 环境。

接下来,你需要激活这个虚拟环境。激活方法取决于你的操作系统:

  • macOS / Linux:
    bash
    source venv/bin/activate
  • Windows (Command Prompt):
    bash
    venv\Scripts\activate.bat
  • Windows (PowerShell):
    powershell
    venv\Scripts\Activate.ps1

激活后,你的终端提示符前会显示 (venv),表示你当前正处于这个虚拟环境中。现在,你在这个环境中安装的所有库都只会存在于 venv 文件夹内,不会污染全局 Python 环境。

1.3 安装 Flask

虚拟环境激活后,我们就可以使用 Python 的包管理工具 pip 来安装 Flask 了。

bash
pip install Flask

等待安装完成。你可以输入 pip list 查看当前环境中安装的库,确认 Flask 是否安装成功。

bash
pip list

你应该能在列表中看到 Flask 和它的一些依赖库,如 Jinja2 (用于模板)、Werkzeug (一个强大的 WSGI 工具集,Flask 建立其上) 等。

至此,你的开发环境已经搭建完毕。

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

现在,让我们来编写 Flask 的经典入门程序——“Hello, World!”。

在你的项目目录下(即 my-flask-app 文件夹),创建一个名为 app.py 的文件。

“`python

app.py

from flask import Flask

创建一个 Flask 应用实例

name 参数是 Python 模块的内置变量,用于指示模块的名称。

Flask 使用这个参数来查找应用所在的根目录,

从而确定静态文件和模板文件的位置。

app = Flask(name)

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

当用户访问应用的根 URL (‘/’) 时,会触发下面的 index 函数。

@app.route(‘/’)
def index():
# 函数返回的内容将作为 HTTP 响应发送给用户的浏览器。
return ‘Hello, World!’

这个条件判断确保只有在直接运行此脚本时(而不是作为模块导入时)

才会执行 app.run()。

if name == ‘main‘:
# app.run() 启动 Flask 的内置开发服务器。
# debug=True 开启调试模式。在调试模式下,当你的代码发生修改时,
# 服务器会自动重新加载;如果发生错误,浏览器会显示一个有用的调试页面。
app.run(debug=True)
“`

保存这个文件。

2.1 运行你的应用

回到你的终端,确保虚拟环境仍然激活,然后运行这个 Python 文件:

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 开发服务器已经启动,并且正在监听 http://127.0.0.1:5000/ 这个地址和端口。127.0.0.1 是本地回环地址,5000 是 Flask 默认使用的端口号。

现在,打开你的 Web 浏览器,访问 http://127.0.0.1:5000/

你应该能在浏览器中看到白底黑字的 “Hello, World!” 文本。

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

你可以尝试修改 index() 函数的返回字符串,保存文件,然后刷新浏览器。由于开启了 debug=True,服务器会自动重新加载,你将看到修改后的内容。

要停止服务器,回到终端,按 Ctrl + C

2.2 代码解析

让我们回顾一下 app.py 的每一部分:

  • from flask import Flask: 导入 Flask 类,它是所有 Flask 应用的基础。
  • app = Flask(__name__): 创建一个 Flask 应用的实例。__name__ 帮助 Flask 确定项目的根目录。
  • @app.route('/'): 这是一个装饰器(decorator)。它将紧随其后的函数注册为一个视图函数,并将其关联到指定的 URL 路径。这里的 '/' 表示应用的根 URL。
  • def index():: 定义了一个 Python 函数。当用户访问 '/' 路径时,Flask 会调用这个函数。
  • return 'Hello, World!': 视图函数必须返回一个响应。最简单的响应就是一个字符串,Flask 会将其作为 HTTP 响应体发送给浏览器。除了字符串,还可以返回 HTML、模板渲染结果、重定向等。
  • if __name__ == '__main__':: 这是 Python 的标准用法,确保 app.run() 只在直接运行 app.py 文件时执行。
  • app.run(debug=True): 启动 Flask 开发服务器。debug=True 开启调试模式,非常方便开发。

3. 核心概念:路由与视图函数

在 Flask 中,Web 应用的核心功能在于将特定的 URL 映射到执行相应逻辑的 Python 函数上。这个映射过程就是路由 (Routing),而处理特定请求的函数就是视图函数 (View Function)

我们已经在“Hello, World!”示例中看到了最简单的路由和视图函数:@app.route('/') 将根路径映射到 index() 函数。

3.1 添加更多路由

一个 Web 应用通常不止一个页面。让我们为应用添加一个“关于我们”页面。

修改 app.py,添加另一个视图函数和路由:

“`python

app.py (添加了关于我们页面)

from flask import Flask

app = Flask(name)

@app.route(‘/’)
def index():
return ‘Hello, World!’

新增的路由和视图函数

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

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

运行 python app.py,然后访问 http://127.0.0.1:5000/http://127.0.0.1:5000/about。你应该能在不同的 URL 上看到不同的内容。

3.2 动态路由

有时候,URL 中包含了一些可变的信息,比如用户 ID 或文章 slug。Flask 允许你使用动态路由来捕获这些信息。

在 URL 规则中使用尖括号 <variable_name> 来定义一个动态部分。这个动态部分会作为参数传递给视图函数。

例如,创建一个用户个人资料页面:

“`python

app.py (添加了动态路由)

from flask import Flask

app = Flask(name)

@app.route(‘/’)
def index():
return ‘Hello, World!’

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

动态路由示例

@app.route(‘/user/‘)
def show_user_profile(username):
# username 会从 URL 中捕获并传递给函数
return f’User: {username}’

带有类型转换的动态路由

表示 post_id 必须是一个整数

@app.route(‘/post/‘)
def show_post(post_id):
# post_id 会被自动转换为整数
return f’Post ID: {post_id}’

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

运行应用,尝试访问 http://1.27.0.0.1:5000/user/alicehttp://127.0.0.1:5000/user/bob。你会看到不同的用户名显示。

再尝试访问 http://127.0.0.1:5000/post/123。你会看到 Post ID。如果你尝试访问 http://127.0.0.1:5000/post/abc,Flask 会返回一个 404 Not Found 错误,因为 'abc' 不能转换为整数。

常用的类型转换器包括:
* string (默认): 接受任何不包含斜杠的字符串。
* int: 接受正整数。
* float: 接受正浮点数。
* path: 接受包含斜杠的字符串。
* uuid: 接受 UUID 字符串。

4. 使用模板:分离逻辑与呈现

目前为止,我们的视图函数直接返回简单的字符串。但在实际的 Web 应用中,页面通常是复杂的 HTML 结构。将 HTML 代码直接写在 Python 字符串中是非常不方便且难以维护的。

这就是模板引擎的作用。模板引擎允许我们将页面的结构(HTML)与应用逻辑(Python 代码)分离开来。Flask 默认集成了 Jinja2 模板引擎,它功能强大且易于使用。

4.1 创建模板文件夹

Flask 会在你的应用根目录下的一个名为 templates 的子文件夹中查找模板文件。所以,首先在你的 my-flask-app 项目文件夹中创建 templates 文件夹。

my-flask-app/
├── venv/
├── app.py
└── templates/
└── index.html <-- 我们将要创建的模板文件

4.2 编写第一个模板

templates 文件夹中创建一个名为 index.html 的文件,写入以下内容:

“`html





My Flask App


Welcome to My Flask App!

Hello, {{ name }}!

This is the homepage rendered from a template.


“`

这个 HTML 文件看起来很标准,但请注意 <p>Hello, {{ name }}!</p> 中的 {{ name }}。这是 Jinja2 模板引擎的语法,用于显示一个变量的值。{{ ... }} 结构表示一个变量或表达式。

4.3 在视图函数中渲染模板

现在,修改 app.py 中的 index() 视图函数,让它不再返回字符串,而是渲染我们刚刚创建的 index.html 模板。我们需要从 flask 模块中导入 render_template 函数。

“`python

app.py (使用模板)

from flask import Flask, render_template # 导入 render_template

app = Flask(name)

@app.route(‘/’)
def index():
# 使用 render_template 函数来渲染模板。
# 第一个参数是模板文件的名称(相对于 templates 文件夹)。
# 后续的关键字参数会将变量传递给模板。
return render_template(‘index.html’, name=’World’) # 传递变量 name

@app.route(‘/about’)
def about():
# 你也可以为其他页面创建模板
return render_template(‘about.html’) # 假设你创建了 about.html

… 其他路由保持不变 …

@app.route(‘/user/‘)
def show_user_profile(username):
return render_template(‘user.html’, username=username) # 传递动态变量

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

可选: 如果你为 /about/user/<username> 也想使用模板,你需要在 templates 文件夹中分别创建 about.htmluser.html 文件。
例如,user.html 可以这样写:
“`html





User Profile

User Profile

Username: {{ username }}


“`

运行 python app.py,访问 http://127.0.0.1:5000/。你将看到一个更漂亮的页面,其中 “Hello, World!” 现在是 “Hello, World!”,因为我们在 render_template 中将 name 变量的值设为了 'World'

尝试修改 return render_template('index.html', name='Alice'),保存并刷新,你会看到页面变成了 “Hello, Alice!”。

4.4 Jinja2 模板基础语法

Jinja2 模板除了变量输出 {{ ... }},还支持一些基本的逻辑和控制结构:

  • 表达式和变量: {{ variable }}{{ user.name }}{{ list[0] }}{{ "Hello" + name }} 等。
  • 控制流: 使用 {% ... %} 结构。
    • If/Else 语句:
      html
      {% if user %}
      <p>Hello, {{ user.name }}!</p>
      {% else %}
      <p>Hello, Guest!</p>
      {% endif %}
    • For 循环:
      html
      <ul>
      {% for item in items %}
      <li>{{ item }}</li>
      {% endfor %}
      </ul>
  • 注释: {# 这是注释 #}
  • 宏 (Macros): 类似函数的模板代码块,可以重复使用。
  • 模板继承: 允许你定义一个基础布局(父模板),然后子模板可以继承父模板并在特定区域(blocks)覆盖或添加内容。这对于构建一致的站点结构非常有用。

虽然在你的第一个应用中可能不会立即用到所有这些高级特性,但了解它们的存在对于构建更复杂的页面至关重要。模板继承是 Jinja2 最强大的特性之一,强烈推荐在后续学习中深入了解。

5. 处理静态文件:CSS, JavaScript 和图片

一个现代的 Web 应用通常包含 CSS 样式表、JavaScript 脚本和图片等文件。这些文件被称为静态文件 (Static Files),因为它们通常是固定不变的,服务器直接将其发送给浏览器,不需要动态生成。

Flask 约定在应用根目录下的一个名为 static 的子文件夹中查找静态文件。

5.1 创建静态文件夹

在你的项目目录下创建 static 文件夹。你可以在其中再创建子文件夹,例如 cssjsimages 等,以更好地组织文件。

my-flask-app/
├── venv/
├── app.py
├── templates/
│ └── index.html
└── static/
└── css/
└── style.css <-- 我们将要创建的静态文件

5.2 编写静态文件

static/css 文件夹中创建一个名为 style.css 的文件,添加一些简单的 CSS 规则:

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

h1 {
color: #0056b3;
}

p {
line-height: 1.6;
}
“`

5.3 在模板中引用静态文件

要在 HTML 模板中引用静态文件,我们需要使用 Flask 提供的 url_for() 函数。url_for() 函数可以根据视图函数的名称生成 URL,它也可以用来生成静态文件的 URL。

在模板中使用 url_for() 生成静态文件 URL 的语法是 {{ url_for('static', filename='...') }}filename 参数是相对于 static 文件夹的路径。

修改 templates/index.html 文件,在 <head> 标签中添加对 style.css 的引用:

“`html





My Flask App


Welcome to My Flask App!

Hello, {{ name }}!

This is the homepage rendered from a template.


“`

运行 python app.py,访问 http://127.0.0.1:5000/。你会看到页面应用了 style.css 中的样式(背景色、字体等)。

url_for() 函数的好处在于,即使你的 URL 路由发生变化,只要静态文件的路径不变,它生成的 URL 依然是正确的,避免了硬编码 URL 带来的维护问题。

6. 处理表单数据: GET 和 POST

Web 应用的一个常见任务是收集用户的输入,例如通过 HTML 表单。用户提交表单时,数据会被发送到服务器,服务器需要接收和处理这些数据。最常见的 HTTP 方法是 GET 和 POST。

  • GET: 数据以 URL 参数的形式发送,适合获取数据或无副作用的操作。数据量有限且不适合传输敏感信息。
  • POST: 数据放在 HTTP 请求体中发送,适合提交数据或有副作用的操作(如创建资源)。数据量理论上无限制且相对更安全(虽然 HTTPS 才是保证传输安全的根本)。

让我们创建一个简单的表单来收集用户的名字,并在另一个页面显示一个问候语。

6.1 创建表单页面模板

templates 文件夹中创建一个 greeting_form.html 文件:

“`html





Greet Me

Enter Your Name





``
这个表单使用
POST方法将数据发送到{{ url_for(‘greet’) }}生成的 URL。输入字段的name=”username”` 属性是关键,它定义了数据发送到服务器时的键名。

6.2 创建处理表单的视图函数

我们需要一个视图函数来渲染表单页面,以及另一个视图函数来处理表单提交的数据。

app.py 中添加以下代码:

“`python

app.py (处理表单)

from flask import Flask, render_template, request, redirect, url_for # 导入 request, redirect, url_for

app = Flask(name)

… 其他路由保持不变 …

用于显示表单的路由,接受 GET 方法

@app.route(‘/form’)
def show_form():
return render_template(‘greeting_form.html’)

用于处理表单提交的路由,接受 POST 方法

注意 methods 参数指定了这个路由只响应 POST 请求

@app.route(‘/greet’, methods=[‘POST’])
def greet():
# 检查请求方法是否为 POST (虽然路由已经限定了,这里是一种额外的检查)
if request.method == ‘POST’:
# request.form 是一个字典状对象,包含了 POST 请求中表单的数据。
# 通过输入字段的 name 属性来获取对应的值。
username = request.form[‘username’]
# 为了防止 Key Error,也可以使用 request.form.get(‘username’),
# 如果键不存在则返回 None。
# username = request.form.get(‘username’)

    # 现在,我们有了用户的名字,可以渲染一个结果页面或者重定向。
    # 这里我们渲染一个结果页面
    return render_template('greeting_result.html', name=username)

# 如果不是 POST 请求(理论上不会发生因为路由限定了方法),
# 可以重定向回表单页面或其他页面。
return redirect(url_for('show_form')) # 导入 url_for 和 redirect

… 确保 app.run(debug=True) 仍在底部 …

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

6.3 创建结果页面模板

templates 文件夹中创建一个 greeting_result.html 文件:

“`html





Greeting

Greeting

{% if name %}

Hello, {{ name }}!

{% else %}

Hello there!

{% endif %}

Go back to form


“`

注意这里使用了 Jinja2 的 {% if name %} 语法,以防 name 变量没有传递过来。

6.4 测试表单

运行 python app.py
访问 http://127.0.0.1:5000/form。你会看到一个包含输入框和按钮的表单。
在输入框中输入你的名字,然后点击 “Submit”。
你应该会被重定向到 http://127.0.0.1:5000/greet,页面会显示 “Hello, [你的名字]!”。

6.5 处理 GET 表单数据

如果你将表单的 method 改为 GET,并且将 /greet 路由的 methods 也改为 ['GET'] (或者不指定,默认就是 GET),那么你需要使用 request.args 而不是 request.form 来获取数据:

“`python

示例:处理 GET 表单数据 (不建议用于敏感信息)

from flask import Flask, render_template, request

app = Flask(name)

@app.route(‘/greet_get’, methods=[‘GET’])
def greet_get():
# request.args 包含 GET 请求的 URL 参数
username = request.args.get(‘username’, ‘Guest’) # 使用 .get() 方法,如果参数不存在则返回默认值 ‘Guest’
return f’Hello, {username} (from GET request)!’

在模板中将 action 指向 /greet_get,method 改为 GET

“`

访问 http://127.0.0.1:5000/form,输入名字,点击提交。注意看浏览器地址栏,你会看到名字出现在 URL 中,例如 http://127.0.0.1:5000/greet_get?username=YourName

在大多数提交数据的场景中,尤其是涉及创建、修改、删除资源时,应该使用 POST 方法。GET 方法主要用于查询和获取信息。

7. 组织你的项目结构

随着你的应用变得越来越复杂,所有的代码都放在一个 app.py 文件中会变得难以管理。一个好的项目结构可以提高代码的可读性和可维护性。

对于初学者和小型应用来说,一个常见的 Flask 项目结构如下:

my-flask-app/
├── venv/ # 虚拟环境文件夹
├── app.py # 主应用文件
├── requirements.txt # 项目依赖列表 (可选但强烈推荐)
├── static/ # 存放静态文件 (CSS, JS, 图片等)
│ ├── css/
│ │ └── style.css
│ └── js/
│ └── script.js
└── templates/ # 存放 HTML 模板文件
├── index.html
├── about.html
├── user.html
├── greeting_form.html
└── greeting_result.html

requirements.txt 文件:

这是一个记录项目所需库及其版本的标准文件。你可以使用 pip freeze > requirements.txt 命令生成它,然后在其他环境中使用 pip install -r requirements.txt 来安装所有依赖。这对于团队协作或部署应用非常重要。

在激活虚拟环境后,运行:
bash
pip freeze > requirements.txt

这会在你的项目根目录下生成 requirements.txt 文件,内容类似:
Flask==2.3.2
Jinja2==3.1.2
Werkzeug==2.3.7
... (其他依赖)

对于更大型的应用,你可能会将代码分割成多个模块(使用 Flask 的蓝图 Blueprint),并将配置、模型、视图等放在不同的文件甚至子目录中。但在入门阶段,上述结构已经足够。

8. 调试技巧

在开发过程中,遇到错误是常有的事。Flask 提供了一些有用的调试工具:

  • debug=True: 我们已经在 app.run(debug=True) 中使用了。它提供了两个主要好处:
    1. 自动重载: 保存代码修改后,服务器会自动重启,无需手动停止和启动。
    2. 交互式调试器: 当应用发生未捕获的异常时,浏览器会显示一个详细的错误页面,并提供一个交互式的 Python shell,你可以在其中检查变量、执行代码,帮助你定位问题。注意: 在生产环境中绝对不要开启 debug=True,因为它会暴露应用内部信息,存在安全风险。
  • print() 语句: 最简单直接的调试方法。在视图函数或其他地方使用 print() 语句,输出会在运行服务器的终端中显示。
  • 日志记录: 对于更正式的调试和错误追踪,可以使用 Python 内置的 logging 模块来记录应用运行时的信息。Flask 应用实例 app 本身也有一个 logger 对象可供使用。

9. 下一步:进阶学习方向

恭喜你!你已经成功构建并运行了你的第一个 Flask Web 应用,掌握了 Flask 的核心概念:应用实例、路由、视图函数、模板、静态文件和表单处理。

这只是 Flask 世界的冰山一角。接下来,你可以探索以下方向,让你的应用更加强大和完善:

  • 数据库集成: 大多数 Web 应用都需要与数据库交互来存储和检索数据。你可以学习如何将 Flask 与数据库(如 SQLite, PostgreSQL, MySQL)集成,通常会使用 ORM (对象关系映射) 工具,如 SQLAlchemy 或 Flask-SQLAlchemy 扩展。
  • 表单处理库: 手动处理表单验证和渲染会很繁琐。Flask-WTF 是一个流行的 Flask 扩展,它集成了 WTForms 库,简化了表单创建、渲染和验证的过程。
  • 用户认证和授权: 如何让用户注册、登录,并控制他们访问特定资源的权限?Flask-Login 是一个常用的用户认证扩展。
  • RESTful API: 除了传统的 Web 页面应用,Flask 也非常适合构建提供数据服务的 RESTful API。
  • Flask 扩展: Flask 社区提供了大量的扩展,覆盖了数据库、认证、缓存、管理后台、调试工具等方方面面,可以极大地提高开发效率。
  • 蓝图 (Blueprints): 对于大型应用,使用蓝图可以将应用分解成更小的、可重用的模块,每个模块可以有自己的路由、模板和静态文件目录。
  • 错误处理: 自定义 404 页面、500 错误页面等。
  • 测试: 编写自动化测试来确保你的应用按预期工作。
  • 部署: 将你的 Flask 应用部署到生产服务器上,让全世界都能访问(例如使用 Gunicorn 或 uWSGI 作为 WSGI 服务器,搭配 Nginx 或 Apache 作为反向代理)。

10. 总结

在本文中,我们从零开始,一步步搭建了 Flask 开发环境,创建了第一个“Hello, World!”应用。我们学习了如何定义路由和视图函数,如何使用 Jinja2 模板将页面结构与逻辑分离,如何处理 CSS 等静态文件,以及如何处理 HTML 表单提交的数据。

Flask 的简洁和灵活性使其成为入门 Web 开发的极佳选择。通过动手实践,你已经迈出了重要的一步。

Web 开发是一个不断学习和探索的过程。继续编写代码,尝试构建更复杂的应用,阅读 Flask 官方文档和社区资源,你将能够掌握更多技能,开发出功能强大、用户友好的 Web 应用。

祝你在 Flask 的学习旅程中一切顺利!享受创造的乐趣吧!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部