PythonFlask教程展示了如何使用PythonFlask模块创建Python网络应用程序。
烧瓶
Flask是Python微型网络框架。它只包含一个核心库。大部分功能都可以作为扩展使用,包括验证、表单处理、对象关系映射器或身份验证。Flask基于WerkzeugWSGI工具包和Jinja2模板引擎。
Web服务器网关接口(WSGI)是Web服务器将请求转发到使用Python编程语言编写的Web应用程序或框架的简单调用约定。
烧瓶Jinja2
Jinja2是一个Flask模板引擎。模板引擎或模板处理器是一个库,旨在将模板与数据模型相结合以生成文档。模板引擎通常用于生成大量电子邮件、源代码预处理或生成动态HTML页面。
通过Jinja教程了解有关Jinja2的更多信息。
网址
统一资源定位器(URL)是对网络资源的引用,指定其在计算机网络上的位置以及检索它的机制。网络资源是可以通过网络获取的任何数据,例如HTML文档、PDF文件、PNG图像、JSON数据或纯文本。
通用URL具有以下形式:
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
[]
括号之间的部分是可选的。
烧瓶安装
$ 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
我们为应用程序创建一个目录。
#!/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
环境变量并使用flaskrun
命令启动应用程序。默认的Flask端口是5000。
$ curl localhost:5000 Hello there!
我们使用curl
命令创建一个请求。
Flask查询参数
查询字符串是URL的一部分,用于为资源请求添加一些条件。它通常是一系列键/值对。它遵循路径并以?
字符开头。
#!/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
我们导入Flask
和request
对象。
@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
当没有设置查询参数时,使用默认值。
烧瓶路径参数
值可以通过查询参数或路径参数发送到网络应用程序。路径参数在尖括号之间指定:。
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
变量。
$ curl localhost:5000/greet/Robert/ Hello Robert
烧瓶make_response
使用make_response
辅助函数,我们可以创建对客户端的响应,包括必要的标头。
#!/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/
POST请求路径。是一个路径变量,其值被传递给
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请求。
烧瓶发送文件
send_file
方法将文件的内容发送到客户端。
#!/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')
我们指定文件名和内容类型。
烧瓶JSON
JSON是一种轻量级数据交换格式。它易于人类阅读和机器解析和生成。Web应用程序经常使用和生成JSON数据。
当向客户端返回Python字典时,Flask会自动将其转换为JSON。可以使用jsonify
函数将其他对象转换为JSON。
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"]
这里我们得到一部随机电影。
烧瓶渲染模板
render_template
函数从具有给定上下文的模板文件夹中呈现模板。上下文是模板上下文中应该可用的变量。存放模板文件的目录默认名称为templates
。
app.py templates index.html
这些是项目目录的内容。
#!/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
下的模板中可用。
<!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
这是项目结构。
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')
我们在应用程序中有两条路线。首页呈现一个模板,模板引用一张图片。关于页面返回一个带有send_static_file
函数的静态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文件。没有模板指令。
<!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页面
HTTP404、404NotFound、404、PageNotFound错误消息是网络通信中使用的超文本传输协议(HTTP)标准响应代码。它表示浏览器能够与给定服务器通信,但服务器找不到所请求的内容。
Flask有一个内置的abort
函数,它向客户端发送错误信息。我们可以使用errorhandler
自定义错误页面。它是一个装饰器,用于通过代码或异常类注册一个函数来处理错误。
#!/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
在示例中,我们为404notfound错误注册了一个错误处理函数。它呈现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>
这是向用户显示的错误页面。
FlaskSQLite示例
在下面的示例中,我们从SQLite数据库发送数据。我们使用SQLAlchemy。
app.py data cities.sql test.db
这是项目结构。
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
数据库中。
#!/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}]}
在本教程中,我们介绍了用于开发Web应用程序的PythonFlask模块。
列出所有Python教程。