Skip to content

入门

https://github.com/pallets/flask

https://flask.palletsprojects.com/

Hello Flask!

1
2
3
4
5
6
7
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
    return '<h1>Hello World!</h1>'
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

动态 URL

可以在 URL 规则中添加变量部分,使用 "<变量名>" 的形式表示。Flask 处理请求时会把变量传入视图函数,所以我们可以添加参数获取这个变量值

1
2
3
@app.route('/greet/<name>')
def greet(name):
    return f"<h1>Hello, {name}!</h1>"

因为 URL 中可以包含变量,所以我们将传入 app.route() 的字符串称为 URL 规则,而不是 URL。Flask 会解析请求并把请求的 URL 与视图函数的 URL 规则进行匹配。比如,这个 greet 视图的 URL 规则为 /greet/<name>,那么类似 /greet/foo/greet/bar 的请求都会触发这个视图函数

这个视图返回的响应会随着请求 URL 中的 name 变量而变化。假设程序运行在 http://helloflask.com 上,当我们在浏览器里访问 http://helloflask.com/greet/Grey 时,可以看到浏览器上显示 "Hello, Grey!"

当 URL 规则中包含变量时,如果用户访问的 URL 中没有添加变量,比如 /greet,那么 Flask 在匹配失败后会返回一个 404 错误响应。一个很常见的行为是在 app.route() 装饰器里使用 defaults 参数设置 URL 变量的默认值,这个参数接收字典作为输入,存储 URL 变量和默认值的映射。在下面的代码中,我们为 greet 视图新添加了一个 app.route() 装饰器,为 /greet 设置了默认的 name 值

1
2
3
4
@app.route('/greet', defaults={'name': 'Programmer'})
@app.route('/greet/<name>')
def greet(name):
    return f"<h1>Hello, {name}!</h1>"

这时如果访问 /greet,那么变量 name 会使用默认值 Programmer,视图函数返回 <h1>Hello, Programmer!</h1>。上面的用法实际效果等同于

1
2
3
4
@app.route('/greet')
@app.route('/greet/<name>')
def greet(name='Programmer'):
    return f"<h1>Hello, {name}!</h1>"

URL 与端点

在 Web 程序中,URL 无处不在。如果程序中的 URL 都是以硬编码的方式写出,那么将会大大降低代码的易用性。比如,当你修改了某个路由的 URL 规则,那么程序里对应的 URL 都要一个一个进行修改。更好的解决办法是使用 Flask 提供的 url_for() 函数获取 URL,当路由中定义的 URL 规则被修改时,这个函数总会返回正确的 URL

调用 url_for() 函数时,第一个参数为端点(endpoint)值。在 Flask 中,端点用来标记一个视图函数以及对应的 URL 规则。端点的默认值为视图函数的名称。

比如,下面的视图函数

1
2
3
@app.route('/')
def index():
    return 'Hello Flask!'

这个路由的端点即视图函数的名称 index,调用 url_for('index') 即可获取对应的 URL,即 "/"

如果 URL 含有动态部分,那么我们需要在 url_for() 函数里传入相应的参数,以下面的视图函数为例

1
2
3
@app.route('/hello/<name>')
def greet(name):
    return f"Hello {name}!"

这时使用url_for('greet', name='Jack')得到的 URL 为 "/hello/Jack"

我们使用 url_for() 函数生成的 URL 是相对 URL(即内部 URL),即 URL 中的 path 部分,比如 "/hello",不包含根 URL。相对 URL 只能在程序内部使用。如果你想要生成供外部使用的绝对 URL,可以在使用 url_for() 函数时,将 _external 参数设为 True,这会生成完整的 URL,比如 http://helloflask.com/hello,在本地运行程序时则会获得 http://localhost:5000/hello

Flask 命令

除了 Flask 内置的 flask run 等命令,我们也可以自定义命令。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
flask --help

Usage: flask [OPTIONS] COMMAND [ARGS]...

  A general utility script for Flask applications.

  Provides commands from Flask, extensions, and the application. Loads the
  application defined in the FLASK_APP environment variable, or from a
  wsgi.py file. Setting the FLASK_ENV environment variable to 'development'
  will enable debug mode.

    $ export FLASK_APP=hello.py
    $ export FLASK_ENV=development
    $ flask run

Options:
  --version  Show the flask version
  --help     Show this message and exit.

Commands:
  routes  Show the routes for the app.
  run     Run a development server.
  shell   Run a shell in the app context.

模板与静态文件

一个完整的网站当然不能只返回用户一句 “Hello, World!”,我们需要模板(template) 和静态文件(static file)来生成更加丰富的网页。模板即包含程序页面的 HTML 文件,静态文件则是需要在 HTML 文件中加载的 CSS 和 JavaScript 文件,以及图片、字体文件等资源文件。默认情况下,模板文件存放在项目根目录中的 templates 文件夹中,静态文件存放在 static 文件夹下,这两个文件夹需要和包含程序实例的模块处于同一个目录下,对应的项目结构示例如下所示:

1
2
3
4
hello/
    - templates/
    - static/
    - app.py

在开发 Flask 程序时,使用 CSS 框架和 JavaScript 库时很常见的需求,而且有很多扩展都提供了对 CSS 框架和 JavaScript 库的集成功能。
使用这些扩展时都需要加载对应的 CSS 和 JavaScript 文件,通常这些扩展都会提供一些可以在 HTML 模板中使用的加载方法/函数,使用这些方法即可渲染出对应的 link 标签和 script 标签。
这些方法一般会直接从 CDN 加载资源,有写提供了手动传入资源 URL 的功能,有些甚至提供了内置的本地资源

建议在开发环境下使用本地资源,这样可以提高加载速度。
最好自己下载到 static 目录下,统一管理,出于方便的考虑也可以使用扩展内置的本地资源。
在过渡到生产环境时,自己手动管理所有本地资源或自己设置 CDN,避免使用扩展内置的资源。
这个建议主要基于下面这些考虑因素:

  • 鉴于国内的网络状况,扩展默认使用的国外 CDN 可能会无法访问,或访问过慢
  • 不同扩展内置的加载方法可能会加载重复的依赖资源,比如 jQuery
  • 在生产环境下,将静态文件集中在一起更方便管理
  • 扩展内置的资源可能会出现版本过旧的情况

注:
CDN 指分布式服务器系统。服务商把你需要的资源存储在分布于不同地理位置的多个服务器,它会根据用户的地理位置来就近分配服务器提供服务(服务器越近,资源传送就越快)。
使用 CDN 服务可以加快网页资源的加载速度,从而优化用户体验。
对于开源的 CSS 和 JavaScript 库,CDN 提供商通常会免费提供服务

Flask 与 MVC 架构

你也许会困惑为什么用来处理请求并生成响应的函数被称为“视图函数(view function)”,其实这个命名并不合理。
在 Flask 中,这个命名的约定来自 Werkzeug,而 Werkzeug 中 URL 匹配的实现主要参考了 Routes(一个 URL 匹配库),再往前追溯,Routes 的实现又参考了 Ruby on Rails(http://rubyonrails.org/)。
在 Ruby on Rails 中,术语 views 用来表示 MVC(Model-View-Controller,模型-视图-控制器)架构中的 View

MVC 架构最初是用来设计桌面程序的,后来也被用于 Web 程序,应用了这种架构的 Web 框架有 Django、Ruby on Rails 等。
在 MVC 架构中,程序被分为三个组件: 数据处理(Model)、用户界面(View)、交互逻辑(Controller)。
如果套用 MVC 架构的内容,那么 Flask 中视图函数的名称其实并不严谨,使用控制器函数(Controller Function)似乎更合适些,虽然它也附带处理用户界面。
严格来说,Flask 并不是 MVC 架构的框架,因为它没有内置数据模型支持。