ZetCode

Python Flask

最后修改于 2024 年 1 月 29 日

Python Flask 教程展示了如何使用 Python Flask 模块创建 Python Web 应用程序。

Flask

Flask 是一个 Python 微型 Web 框架。它仅包含一个核心库。 大部分功能都以扩展的形式提供,包括验证、表单处理、对象关系映射器或身份验证。 Flask 基于 Werkzeug WSGI 工具包和 Jinja2 模板引擎。

Web 服务器网关接口 (WSGI) 是一种简单的调用约定,用于将 Web 服务器的请求转发到用 Python 编程语言编写的 Web 应用程序或框架。

Flask Jinja2

Jinja2 是一个 Flask 模板引擎。 模板引擎或模板处理器是一个库,旨在将模板与数据模型相结合以生成文档。 模板引擎通常用于生成大量电子邮件、源代码预处理或生成动态 HTML 页面。

通过Jinja 教程了解更多关于 Jinja2 的信息。

URL

统一资源定位符 (URL) 是对 Web 资源的引用,它指定了该资源在计算机网络上的位置以及检索它的机制。 Web 资源是可以经由 Web 获得的任何数据,例如 HTML 文档、PDF 文件、PNG 图像、JSON 数据或纯文本。

通用 URL 的形式如下:

scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]

[]括号之间的部分是可选的。

Flask 安装

$ pip3 install -U Flask

我们使用 pip3 工具来安装 Flask。 -U--update 将模块更新到最新版本。

设置虚拟环境

更复杂的应用程序在开发期间使用虚拟环境。

$ python3 -m venv venv
. venv/bin/activate

这些命令在 Linux 上创建一个新的虚拟环境。

> py -3 -m venv venv
> venv\Scripts\activate

这些命令在 Windows 上创建一个新的虚拟环境。

运行 Flask 应用程序

推荐的运行 Flask 应用程序的方式是借助环境变量。

$ export FLASK_APP=hello.py
$ flask run

我们将 FLASK_APP 设置为主应用程序文件的名称。 在 Windows 上,使用 set 命令代替 export

$ export FLASK_ENV=development

要在开发模式下运行 Flask 应用程序,我们还需要设置 FLASK_EVN 变量。

Flask 简单示例

在以下示例中,我们创建一个简单的 Flask 应用程序。

$ mkdir hello
$ cd hello

我们为应用程序创建一个目录。

hello.py
#!/usr/bin/python

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello there!'

在一个目录中,我们创建一个 Python 文件 hello.py

from flask import Flask

我们导入 Flask 对象。 它实现了一个 WSGI 应用程序并充当中心对象。

@app.route('/')
def hello():
    return 'Hello there!'

使用 @app.route 装饰器,我们定义一个路由。 路由是 URL 和 Web 应用程序功能之间的映射。 在我们的例子中,我们返回一个简单的文本消息。

$ flask run
* Serving Flask app "hello.py"
* Environment: production
  WARNING: This is a development server. Do not use it in a production deployment.
  Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

我们设置 FLASK_APP 环境变量并使用 flask run 命令启动应用程序。 默认的 Flask 端口是 5000。

$ curl localhost:5000
Hello there!

我们使用 curl 命令创建了一个请求。

Flask 查询参数

查询字符串是 URL 的一部分,用于向资源请求添加一些条件。 它通常是一系列键/值对。 它遵循路径并以 ? 字符开头。

app.py
#!/usr/bin/python

from flask import Flask, request

app = Flask(__name__)


@app.route('/')
def index():

    return 'Home page'


@app.route('/greet', methods=['GET'])
def greet():

    name = request.args.get('name', 'Guest')
    msg = f'Hello {name}'

    return msg, 200, {'Content-Type': 'text/plain; charset=utf-8'}

应用程序创建并向客户端发送一条消息。 它使用来自 name 查询参数的值。

from flask import Flask, request

我们导入 Flaskrequest 对象。

@app.route('/greet', methods=['GET'])
def greet():
...

greet 函数映射到 /greet 路径和 GET 类型请求。

name = request.args.get('name', 'Guest')

我们使用 get 方法从 request 对象获取查询参数。 如果参数不存在,则返回默认值 'Guest'

msg = f'Hello {name}'

我们将 name 查询参数的值包含到消息中。

return msg, 200, {'Content-Type': 'text/plain; charset=utf-8'}

我们将消息、状态码和响应内容类型返回给客户端。

$ export FLASK_APP=app.py
$ flask run

我们运行应用程序。

$ curl -i localhost:5000/greet?name=Lucia
HTTP/1.0 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 11
Server: Werkzeug/0.16.0 Python/3.8.0
Date: Thu, 16 Jan 2020 15:50:58 GMT

Hello Lucia

我们创建一个对应用程序的 GET 请求。 使用 -i 选项,我们还包括响应头。

$ curl localhost:5000/greet
Hello Guest

当未设置查询参数时,将使用默认值。

Flask 路径参数

值可以通过查询参数或路径参数发送到 Web 应用程序。 路径参数在尖括号之间指定:<param>

app.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():

    return 'Home page'


@app.route("/greet/<name>/")
def greet(name):

    msg = f'Hello {name}'

    return msg, 200, {'Content-Type': 'text/plain; charset=utf-8'}

应用程序向用户返回问候语,用户的姓名指定为路径参数。

@app.route("/greet/<name>/")
def greet(name):

路径参数在此处定义:<name>。 然后,该参数传递给 name 变量。

$ curl localhost:5000/greet/Robert/
Hello Robert

Flask make_response

使用 make_response 辅助函数,我们可以创建对客户端的响应,包括必要的标头。

app.py
#!/usr/bin/python

from flask import Flask, make_response

app = Flask(__name__)


@app.route('/')
def hello():
    return 'Home page'


@app.route('/users/<name>', methods=['POST'])
def create_user(name):

    msg = f'user {name} created'
    return make_response(msg, 201)


@app.route('/users/<name>', methods=['GET'])
def get_user(name):

    msg = f'Hello {name}'
    return make_response(msg, 200)

该应用程序由一个文件组成:app.py。 它包含三个方法。

@app.route('/')
def hello():
    return 'Home page'

对于主页,我们返回一条简单的文本消息。

@app.route('/users/<name>', methods=['POST'])
def create_user(name):

    msg = f'user {name} created'
    return make_response(msg, 201)

create_user 方法映射到 /users/<name> 路径和 POST 请求。 <name> 是一个路径变量,其值传递给 name 变量。 make_response 创建一个带有正文和 201 状态码的响应。

@app.route('/users/<name>', methods=['GET'])
def get_user(name):

    msg = f'Hello {name}'
    return make_response(msg, 200)

get_user 映射到同一路径,但方法不同:GET。 这次响应包含 200 状态码。

$ export FLASK_APP=app.py
$ flask run

我们运行应用程序。

$ curl -i localhost:5000/users/Peter/
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 11
Server: Werkzeug/0.16.0 Python/3.8.0
Date: Thu, 16 Jan 2020 15:31:37 GMT

Hello Peter

我们创建一个对应用程序的 GET 请求。

$ curl -X POST localhost:5000/users/Peter/
user Peter created

创建一个 POST 请求。

Flask send_file

send_file 方法将文件的内容发送给客户端。

app.py
#!/usr/bin/python

from flask import Flask, send_file

app = Flask(__name__)

@app.route('/image')
def get_image():

    filename = 'sid.png'
    return send_file(filename, mimetype='image/png')

该示例将图像发送给客户端。

return send_file(filename, mimetype='image/png')

我们指定文件名和内容类型。

Flask JSON

JSON 是一种轻量级的数据交换格式。它易于人类阅读,也易于机器解析和生成。Web 应用程序通常会消耗和生成 JSON 数据。

当将 Python 字典返回给客户端时,Flask 会自动将其转换为 JSON。 可以使用 jsonify 函数将其他对象转换为 JSON。

app.py
from flask import Flask, jsonify, render_template
import random

app = Flask(__name__)

movies = {1: 'Toy story', 2: 'The Raid', 3: 'Hero',
            4: 'Ip Man', 5: 'Kung Fu Panda'}


@app.route('/movies')
def get_movies():

    return movies


@app.route('/rmovie')
def random_movie():

    movie = random.choice(list(movies.items()))

    return jsonify(movie)

在该示例中,我们有两个函数。 一个返回字典,另一个返回字典中的随机对。

@app.route('/movies')
def get_movies():

    return movies

Flask 自动将 movies 字典转换为 JSON。

@app.route('/rmovie')
def random_movie():

    movie = random.choice(list(movies.items()))

    return jsonify(movie)

此函数从字典返回一个随机电影;它是一个 Python 元组。 然后使用 jsonify 函数将元组转换为 JSON。

$ curl localhost:5000/movies
{"1":"Toy story","2":"The Raid","3":"Hero","4":"Ip Man","5":"Kung Fu Panda"}

在这里,我们获取所有电影作为 JSON 数据。

$ curl localhost:5000/rmovie
[2,"The Raid"]

在这里,我们获得一部随机电影。

Flask render_template

render_template 函数使用给定的上下文呈现模板文件夹中的模板。 上下文是应在模板上下文中可用的变量。 存储模板文件的目录的默认名称是 templates

app.py
templates
    index.html

这是项目目录的内容。

app.py
#!/usr/bin/python

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/greet/<name>/')
def greet(name):

    msg = f'Hello {name}'

    return render_template('index.html', name=name)

在该示例中,我们从路径参数读取一个值并将其发送到 index.html 模板文件进行处理。

return render_template('index.html', name=name)

render_template 的第一个参数是模板文件名,第二个参数是上下文变量。 name 局部变量将在模板中以 name 提供。

templates/index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Greeting</title>
</head>

<body>

    <p>
        Hello {{ name }}
    </p>

</body>

</html>

这是 index.html 模板文件。 该模板由静态数据和动态数据组成。

<p>
  Hello {{ name }}
</p>

使用 {{}} 语法,我们输出传递给模板的 name 变量的值。

$ curl localhost:5000/greet/Peter/
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Greeting</title>
</head>

<body>

    <p>
        Hello Peter
    </p>

</body>

</html>

Flask 提供静态文件

静态文件是不更改的文件。 它们包括 CSS 文件、JavaScript 文件和图像; 也不包含模板指令的 HTML 文件。 Flask 具有用于静态文件的默认 static 目录。

app.py
static
    about.html
    sid.jpg
templates
    index.html

这是项目结构。

app.py
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/about')
def about():
    return app.send_static_file('about.html')

应用程序中有两个路由。 主页呈现一个引用图像的模板。 about 页面使用 send_static_file 函数返回一个静态 HTML 文件。

static/about.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>About</title>
</head>
<body>

    <p>
        About page
    </p>
    
</body>
</html>

about.html 页面是一个简单的静态 HTML 文件。 没有模板指令。

templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Home page</title>
</head>
<body>
        
    <img src="/static/sid.jpg" alt="Sid">
    <img src="{{ url_for('static', filename='sid.jpg') }}" alt="Sid">
    
</body>
</html>

index.html 模板文件中,我们引用一个静态资源:一个图像文件。

<img src="/static/sid.jpg" alt="Sid">
<img src="{{ url_for('static', filename='sid.jpg') }}" alt="Sid">

我们将一个 JPEG 图像包含到文件中。 建议使用 url_for 函数,因为硬编码的 URL 更难以维护。

Flask 自定义 404 页面

HTTP 404、404 Not Found、404、Page Not Found 错误消息是 Web 通信中使用的超文本传输协议 (HTTP) 标准响应代码。 它表明浏览器能够与给定的服务器通信,但服务器找不到所请求的内容。

Flask 有一个内置的 abort 函数,它向客户端发送错误消息。 我们可以使用 errorhandler 自定义错误页面。 它是一个装饰器,用于注册一个函数来处理按代码或异常类发生的错误。

app.py
#!/usr/bin/python

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Home page'

@app.route('/about')
def about():
    return 'About page'

@app.errorhandler(404)
def not_found_error(error):
    return render_template('404.html'), 404

在该示例中,我们为 404 未找到错误注册一个错误处理程序函数。 它呈现 404.html 模板文件。

templates/404.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>404 error</title>
</head>
<body>

    <p>
        404 - page not found
    </p>
    
</body>
</html>

这是显示给用户的错误页面。

Flask SQLite 示例

在以下示例中,我们从 SQLite 数据库发送数据。 我们使用 SQLAlchemy。

app.py
data 
  cities.sql 
  test.db

这是项目结构。

cities.sql
BEGIN TRANSACTION;
DROP TABLE IF EXISTS cities;

CREATE TABLE cities(id INTEGER PRIMARY KEY, name TEXT, population INTEGER);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
COMMIT;

我们使用这些数据。

$ sqlite3 test.db
SQLite version 3.27.2 2019-02-25 16:06:06
Enter ".help" for usage hints.
sqlite> .read cities.sql
sqlite> select * from cities;
1|Bratislava|432000
2|Budapest|1759000
3|Prague|1280000
4|Warsaw|1748000
5|Los Angeles|3971000
6|New York|8550000
7|Edinburgh|464000
8|Berlin|3671000

我们将数据加载到 test.db 数据库中。

app.py
#!/usr/bin/python

from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data/test.db'

db = SQLAlchemy(app)


class City(db.Model):
    __tablename__ = 'cities'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    population = db.Column(db.Integer)

    def serialize(self):

        return {
            'id': self.id, 
            'name': self.name,
            'population': self.population,
        }


@app.route('/cities')
def all():

    cities = City.query.all()

    return jsonify(cities=[city.serialize() for city in cities])

应用程序将 cities 表中的所有行作为 JSON 数据发送给客户端。

from flask_sqlalchemy import SQLAlchemy

为了处理数据,我们使用 flask_sqlalchemy 模块。

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

我们不使用 flask_sqlalchemy 事件系统; 因此,我们使用 SQLALCHEMY_TRACK_MODIFICATIONS 配置选项将其关闭。

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data/test.db'

使用 SQLALCHEMY_DATABASE_URI,我们指定数据库的路径。

db = SQLAlchemy(app)

创建一个 SQLAlchemy 对象; 它用于处理数据库。

class City(db.Model):
    __tablename__ = 'cities'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    population = db.Column(db.Integer)

    def serialize(self):

        return {
            'id': self.id, 
            'name': self.name,
            'population': self.population,
        }

这是 City 实体。 我们定义表名并将属性映射到数据库列。 serialize 方法有助于将 Python 类转换为 JSON 对象。

@app.route('/cities')
def all():

    cities = City.query.all()

    return jsonify(cities=[city.serialize() for city in cities])

对于 /cities 路由,我们从数据库中提取所有行并将它们作为 JSON 数据发送给客户端。

$ export FLASK_APP=app.py
$ curl localhost:5000/cities
{"cities":[{"id":1,"name":"Bratislava","population":432000},
{"id":2,"name":"Budapest","population":1759000},
{"id":3,"name":"Prague","population":1280000},
{"id":4,"name":"Warsaw","population":1748000},
{"id":5,"name":"Los Angeles","population":3971000},
{"id":6,"name":"New York","population":8550000},
{"id":7,"name":"Edinburgh","population":464000},
{"id":8,"name":"Berlin","population":3671000}]}

来源

Python Flask 文档

在本文中,我们介绍了 Python Flask 模块,该模块用于开发 Web 应用程序。

作者

我叫 Jan Bodnar,我是一位热情的程序员,拥有丰富的编程经验。 我从 2007 年开始撰写编程文章。 迄今为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程