51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

详细的Python Flask的操作

本篇文章是Python Flask 建站框架入门课程_编程实战微课_w3cschool微课的学习笔记,根据课程整理而来,本人使用版本如下:

| Python | 3.10.0 | |--------|--------| | Flask | 2.2.2 |

简介 {#%E7%AE%80%E4%BB%8B}

  • Flask是一个轻量级的可定制的web框架

  • Flask 可以很好地结合MVC模式进行开发

  • Flask还有很强的很强的扩展性和兼容性

核心函数库 {#%E6%A0%B8%E5%BF%83%E5%87%BD%E6%95%B0%E5%BA%93}

Flask主要包括Werkzeug和Jinja2两个核心函数库,它们分别负责业务处理和安全方面的功能,这些基础函数为web项目开发过程提供了丰富的基础组件。

Werkzeug {#werkzeug}

Werkzeug库十分强大,功能比较完善,支持URL路由请求集成,一次可以响应多个用户的访问请求;

支持Cookie和会话管理,通过身份缓存数据建立长久连接关系,并提高用户访问速度;支持交互式Javascript调试,提高用户体验;

可以处理HTTP基本事务,快速响应客户端推送过来的访问请求。

Jinja2 {#jinja2}

Jinja2库支持自动HTML转移功能,能够很好控制外部黑客的脚本攻击;

系统运行速度很快,页面加载过程会将源码进行编译形成python字节码,从而实现模板的高效运行;

模板继承机制可以对模板内容进行修改和维护,为不同需求的用户提供相应的模板。

安装 {#%E5%AE%89%E8%A3%85}

通过pip安装即可

pip install Flask
# pip3
pip3 install Flask

目录结构 {#%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84}

新项目创建后的结构 {#%E6%96%B0%E9%A1%B9%E7%9B%AE%E5%88%9B%E5%BB%BA%E5%90%8E%E7%9A%84%E7%BB%93%E6%9E%84}

static文件夹:存放静态文件,比如css、js、图片等

templates文件夹:模板文件目录

app.py:应用启动程序

获取URL参数 {#%E8%8E%B7%E5%8F%96url%E5%8F%82%E6%95%B0}

列出所有URL参数 {#%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89url%E5%8F%82%E6%95%B0}

request.args.__str__()

from flask import Flask, request

app = Flask(name)

@app.route('/') def hello_world(): # put application's code here return request.args.str()

ifname== 'main': app.run()


在浏览器中访问http://127.0.0.1:5000/?name=Loen&age&app=ios&app=android,将显示:

ImmutableMultiDict([('name', 'Loen'), ('age', ''), ('app', 'ios'), ('app', 'android')])

列出浏览器传给我们的Flask服务的数据 {#%E5%88%97%E5%87%BA%E6%B5%8F%E8%A7%88%E5%99%A8%E4%BC%A0%E7%BB%99%E6%88%91%E4%BB%AC%E7%9A%84flask%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%95%B0%E6%8D%AE}

from flask import Flask, request

app = Flask(name)

@app.route('/') def hello_world(): # put application's code here

# 列出访问地址
print(request.path)

# 列出访问地址及参数
print(request.full_path)

return request.args.__str__()

ifname== 'main': app.run()


在浏览器中访问http://127.0.0.1:5000/?name=Loen&age&app=ios&app=android,控制台中显示

/
/?name=Loen&age&app=ios&app=android

获取指定的参数值 {#%E8%8E%B7%E5%8F%96%E6%8C%87%E5%AE%9A%E7%9A%84%E5%8F%82%E6%95%B0%E5%80%BC}

from flask import Flask, request

app = Flask(name)

@app.route('/') def hello_world(): # put application's code here

return request.args.get('name')

ifname== 'main': app.run()


在浏览器中访问http://127.0.0.1:5000/?name=Loen&age&app=ios&app=android,将显示:

Loen

处理多值 {#%E5%A4%84%E7%90%86%E5%A4%9A%E5%80%BC}

from flask import Flask, request

app = Flask(name)

@app.route('/') def hello_world(): # put application's code here r = request.args.getlist('app') # 返回一个list return r

ifname== 'main': app.run()


在浏览器中访问http://127.0.0.1:5000/?name=Loen&age&app=ios&app=android,将显示:

[
  "ios",
  "android"
]

获取POST方法传送的数据 {#%E8%8E%B7%E5%8F%96post%E6%96%B9%E6%B3%95%E4%BC%A0%E9%80%81%E7%9A%84%E6%95%B0%E6%8D%AE}

作为一种HTTP请求方法,POST用于向指定的资源提交要被处理的数据。

我们在某些时候不适合将数据放到URL参数中,密或者数据太多,浏览器不一定支持太长长度的URL。这时,一般使用POST方法。

本文章使用python的requests库模拟浏览器。

安装命令:

pip install requests

看POST数据内容 {#%E7%9C%8Bpost%E6%95%B0%E6%8D%AE%E5%86%85%E5%AE%B9}

app.py代码如下:

from flask import Flask, request

app = Flask(name)

@app.route('/register', methods=['POST']) def register(): print(request.headers) print(request.stream.read()) return 'welcome'

ifname== 'main': app.run()


register.py代码如下:

import requests
`if `name` == '`main`':
user_info = {'name': 'Loen', 'password': 'loveyou'}
r = requests.post("http://127.0.0.1:5000/register", data=user_info)
print(r.text)
`

运行app.py,然后运行register.py

register.py将输出:

welcome

app.py将输出:

Host: 127.0.0.1:5000
User-Agent: python-requests/2.28.2
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 26
Content-Type: application/x-www-form-urlencoded
`b'name=Loen&password=loveyou'
127.0.0.1 - - [14/Feb/2023 21:12:17] "POST /register HTTP/1.1" 200 -
`

解析POST数据 {#%E8%A7%A3%E6%9E%90post%E6%95%B0%E6%8D%AE}

app.py代码如下:

from flask import Flask, request

app = Flask(name)

@app.route('/register', methods=['POST']) def register():

print(request.stream.read()) # 不要用,否则下面的form取不到数据

print(request.form) print(request.form['name']) print(request.form.get('name')) print(request.form.getlist('name')) print(request.form.get('nickname', default='little apple')) return 'welcome'

ifname== 'main': app.run(port=5000, debug=True)


register.py代码不变,运行app.py,然后运行register.py

register.py将输出:

welcome

app.py将输出:

ImmutableMultiDict([('name', 'Loen'), ('password', 'loveyou')])
Loen
Loen
['Loen']
little apple

request.form会自动解析数据。

request.form['name']和request.form.get('name')都可以获取name对应的值。

request.form.get()可以为参数default指定值以作为默认值。

获取POST中的列表数据 {#%E8%8E%B7%E5%8F%96post%E4%B8%AD%E7%9A%84%E5%88%97%E8%A1%A8%E6%95%B0%E6%8D%AE}

app.py代码如下:

from flask import Flask, request

app = Flask(name)

@app.route('/register', methods=['POST']) def register():

print(request.stream.read()) # 不要用,否则下面的form取不到数据

print(request.form.getlist('name')) return 'welcome'

ifname== 'main': app.run(port=5000, debug=True)


register.py代码如下:

import requests
`if `name` == '`main`':
user_info = {'name': ['Loen', 'Alan'], 'password': 'loveyou'}
r = requests.post("http://127.0.0.1:5000/register", data=user_info)
print(r.text)
`

运行app.py,然后运行register.py

register.py将输出:

welcome

app.py将输出:

['Loen', 'Alan']

处理和响应JSON数据 {#%E5%A4%84%E7%90%86%E5%92%8C%E5%93%8D%E5%BA%94json%E6%95%B0%E6%8D%AE}

处理JSON数据 {#%E5%A4%84%E7%90%86json%E6%95%B0%E6%8D%AE}

如果POST的数据是JSON格式,request.json会自动将json数据转换成Python类型(字典或者列表)。

app.py代码如下:

from flask import Flask, request

app = Flask(name)

@app.route('/add', methods=['POST']) def add(): print(type(request.json)) print(request.json) result = request.json['n1'] + request.json['n2'] return str(result)

ifname== 'main': app.run(port=5000, debug=True)


register.py代码如下:

import requests
`if `name` == '`main`':
json_data = {'n1': 5, 'n2': 3}
r = requests.post("http://127.0.0.1:5000/add", json=json_data)
print(r.text)
`

运行app.py,然后运行register.py

register.py将输出:

8

app.py将输出:

<class 'dict'>
{'n1': 5, 'n2': 3}

响应JSON数据(Response) {#%E5%93%8D%E5%BA%94json%E6%95%B0%E6%8D%AE%EF%BC%88response%EF%BC%89}

app.py代码如下:

import json

from flask import Flask, request, Response

app = Flask(name)

@app.route('/add', methods=['POST']) def add(): result = {'sum': request.json['n1'] + request.json['n2']} return Response(json.dumps(result), mimetype='application/json')

ifname== 'main': app.run(port=5000, debug=True)


register.py代码如下:

import requests
`if `name` == '`main`':
json_data = {'n1': 5, 'n2': 3}
r = requests.post("http://127.0.0.1:5000/add", json=json_data)
print(r.headers)
print(r.text)
`

运行app.py,然后运行register.py

register.py将输出:

/home/huangge1199/PycharmProjects/flaskProject/venv/bin/python /home/huangge1199/PycharmProjects/flaskProject/register.py 
{'Server': 'Werkzeug/2.2.2 Python/3.7.3', 'Date': 'Tue, 14 Feb 2023 13:37:49 GMT', 'Content-Type': 'application/json', 'Content-Length': '10', 'Connection': 'close'}
{"sum": 8}

响应JSON数据(jsonify) {#%E5%93%8D%E5%BA%94json%E6%95%B0%E6%8D%AE%EF%BC%88jsonify%EF%BC%89}

app.py中app()返回时使用下面的内容,效果同之前一样

return jsonify(result)

上传表单 {#%E4%B8%8A%E4%BC%A0%E8%A1%A8%E5%8D%95}

用 Flask 处理文件上传很简单,只要确保你没忘记在 HTML 表单中设置 enctype="multipart/form-data" 属性,不然你的浏览器根本不会发送文件。

安装响应的库werkzeug

pip install werkzeug

目录结构:

app.py代码如下:

from flask import Flask, request
from werkzeug.utils import secure_filename
import os

app = Flask(name)

文件上传目录

app.config['UPLOAD_FOLDER'] = 'static/uploads/'

支持的文件格式

app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'} # 集合类型

判断文件名是否是我们支持的格式

def allowed_file(filename): return '.' in filename and

filename.rsplit('.', 1)[1] in app.config['ALLOWED_EXTENSIONS']

@app.route('/upload', methods=['POST']) def upload(): upload_file = request.files['image'] if upload_file and allowed_file(upload_file.filename): # 上传前文件在客户端的文件名 filename = secure_filename(upload_file.filename)

将文件保存到 static/uploads 目录,文件名同上传时使用的文件名

upload_file.save(os.path.join(app.root_path, app.config['UPLOAD_FOLDER'], filename)) return 'info is ' + request.form.get('info', '') + '. success' else: return 'failed'

ifname== 'main': app.run()


register.py代码如下:

import requests
`if `name` == "`main`":
file_data = {'image': open('flask.png', 'rb')}
user_info = {'info': 'flask'}
r = requests.post("http://127.0.0.1:5000/upload", data=user_info, files=file_data)
print(r.text)
`

运行app.py,然后运行register.py,这时候文件已经上传到了指定目录中

要控制上产文件的大小,可以设置请求实体的大小,代码如下:

app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 #16MB

获取上传文件的内容,代码如下:

file_content = request.files['image'].stream.read()

Restful URL {#restful-url}

Restful URL可以看做是对 URL 参数的替代

变量规则 {#%E5%8F%98%E9%87%8F%E8%A7%84%E5%88%99}

写法如下:

@app.route('/user/<username>/friends')

转换类型 {#%E8%BD%AC%E6%8D%A2%E7%B1%BB%E5%9E%8B}

使用 Restful URL 得到的变量默认为str对象。我们可以用flask内置的转换机制,即在route中指定转换类型,写法如下:

@app.route('/page/<int:num>')

有3个默认的转换器:

  • int:接受整数

  • float:同 int ,但是接受浮点数

  • path:和默认的相似,但也接受斜线

自定义转换器 {#%E8%87%AA%E5%AE%9A%E4%B9%89%E8%BD%AC%E6%8D%A2%E5%99%A8}

自定义的转换器是一个继承werkzeug.routing.BaseConverter的类,修改to_python和to_url方法即可。

to_python方法用于将url中的变量转换后供被@app.route包装的函数使用,to_url方法用于flask.url_for中的参数转换。

下面是一个示例:

from flask import Flask, url_for
from werkzeug.routing import BaseConverter

class MyIntConverter(BaseConverter):

def __init__(self, url_map):
    super(MyIntConverter, self).__init__(url_map)

def to_python(self, value):
    return int(value)

def to_url(self, value):
    return value * 2

app = Flask(name) app.url_map.converters['my_int'] = MyIntConverter

@app.route('/page/&lt;my_int:num&gt;') def page(num): print(num) print(url_for('page', num='145')) # page 对应的是 page函数 ,num 对应对应/page/&amp;lt;my_int:num&amp;gt;中的num,必须是str return 'hello world'

ifname== 'main': app.run()


运行app.py,浏览器访问http://127.0.0.1:5000/page/28后,app.py的输出信息是:

28
/page/145145

使用url_for生成链接 {#%E4%BD%BF%E7%94%A8url_for%E7%94%9F%E6%88%90%E9%93%BE%E6%8E%A5}

工具函数url_for可以让你以软编码的形式生成url,提供开发效率。

例子app.py代码如下:

from flask import Flask, url_for

app = Flask(name)

@app.route('/') def hello_world(): pass

@app.route('/user/&lt;name&gt;') def user(name): pass

@app.route('/page/&lt;int:num&gt;') def page(num): pass

@app.route('/test') def test(): print(url_for('test')) print(url_for('user', name='loen')) print(url_for('page', num=1, q='welcome to w3c 15%2')) print(url_for('static', filename='uploads/flask.png')) return 'Hello'

ifname== 'main': app.run()


运行app.py。然后在浏览器中访问http://127.0.0.1:5000/testserver.py控制台将输出以下信息:

/test
/user/loen
/page/1?q=welcome+to+w3c+15%252
/static/uploads/flask.jpg

使用redirect重定向网址 {#%E4%BD%BF%E7%94%A8redirect%E9%87%8D%E5%AE%9A%E5%90%91%E7%BD%91%E5%9D%80}

在浏览器中访问http://127.0.0.1:5000/old,浏览器的url会变成http://127.0.0.1:5000/new,并显示,app.py代码如下:

from flask import Flask, url_for, redirect

app = Flask(name)

@app.route('/old') def old(): print('this is old') return redirect(url_for('new'))

@app.route('/new') def new(): print('this is new') return 'this is new'

ifname== 'main': app.run()


运行app.py,然后在浏览器中访问http://127.0.0.1:5000/old

浏览器显示:

this is new

控制台显示:

this is old
this is new

自定义404 {#%E8%87%AA%E5%AE%9A%E4%B9%89404}

处理HTTP错误 {#%E5%A4%84%E7%90%86http%E9%94%99%E8%AF%AF}

要处理HTTP错误,可以使用flask.abort函数。

app.py代码如下:

from flask import Flask, abort

app = Flask(name)

@app.route('/user') def user(): abort(401) # Unauthorized 未授权 print('Unauthorized, 请先登录')

ifname== 'main': app.run()


运行app.py,然后在浏览器中访问http://127.0.0.1:5000/user

浏览器显示:

自定义错误页面 {#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%94%99%E8%AF%AF%E9%A1%B5%E9%9D%A2}

page_unauthorized 函数返回的是一个元组,401 代表HTTP 响应状态码。

如果省略401,则响应状态码会变成默认的 200。

app.py代码如下:

from flask import Flask, abort, render_template_string

app = Flask(name)

@app.route('/user') def user(): abort(401) # Unauthorized

@app.errorhandler(401) def page_unauthorized(error): return render_template_string('&lt;h1&gt; Unauthorized &lt;/h1&gt;&lt;h2&gt;{{ error_info }}&lt;/h2&gt;', error_info=error), 401

ifname== 'main': app.run()


运行app.py,然后在浏览器中访问http://127.0.0.1:5000/user

浏览器显示:

用户会话 {#%E7%94%A8%E6%88%B7%E4%BC%9A%E8%AF%9D}

session 用来记录用户的登录状态,一般基于cookie实现。

app.py代码如下:

from flask import Flask, render_template_string, request, session, redirect, url_for

app = Flask(name)

app.secret_key = 'LoenDSdtj\9bX#%@!!*(0&amp;^%)'

@app.route('/login') def login(): page = ''' &lt;form action="{{ url_for('do_login') }}" method="post"&gt; &lt;p&gt;name: &lt;input type="text" name="user_name" /&gt;&lt;/p&gt; &lt;input type="submit" value="Submit" /&gt; &lt;/form&gt; ''' return render_template_string(page)

@app.route('/do_login', methods=['POST']) def do_login(): name = request.form.get('user_name') session['user_name'] = name return 'success'

@app.route('/show') def show(): return session['user_name']

@app.route('/logout') def logout(): session.pop('user_name', None) return redirect(url_for('login'))

ifname== 'main': app.run()


代码的含义

app.secret_key用于给session加密。

在/login中将向用户展示一个表单,要求输入一个名字,submit后将数据以post的方式传递给/do_login,/do_login将名字存放在session中。

如果用户成功登录,访问/show时会显示用户的名字。此时,打开调试工具,选择session面板,会看到有一个cookie的名称为session。

/logout用于登出,通过将session中的user_name字段pop即可。Flask中的session基于字典类型实现,调用pop方法时会返回pop的键对应的值;如果要pop的键并不存在,那么返回值是pop()的第二个参数。

另外,使用redirect()重定向时,一定要在前面加上return。

设置session的有效时间 {#%E8%AE%BE%E7%BD%AEsession%E7%9A%84%E6%9C%89%E6%95%88%E6%97%B6%E9%97%B4}

设置session的有效时间设置为5分钟。

代码如下:

from datetime import timedelta
from flask import session, app
`session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=5)
`

使用Cookie {#%E4%BD%BF%E7%94%A8cookie}

Cookie是存储在客户端的记录访问者状态的数据。

常用的用于记录用户登录状态的session大多是基于cookie实现的。

cookie可以借助flask.Response来实现。

使用Response.set_cookie添加和删除cookie。

expires参数用来设置cookie有效时间,值可以是datetime对象或者unix时间戳。

res.set_cookie(key='name', value='loen', expires=time.time()+6*60)

上面的expire参数的值表示cookie在从现在开始的6分钟内都是有效的。

要删除cookie,将expire参数的值设为0即可:

res.set_cookie('name', '', expires=0)

详细的app.py代码如下:

import time

from flask import Flask, request, Response

app = Flask(name)

@app.route('/add') def login(): res = Response('add cookies') res.set_cookie(key='name', value='loen', expires=time.time() + 6 * 60) return res

@app.route('/show') def show(): return request.cookies.str()

@app.route('/del') def del_cookie(): res = Response('delete cookies') res.set_cookie('name', '', expires=0) return res

if name == 'main': app.run()


闪存系统 flashing system {#%E9%97%AA%E5%AD%98%E7%B3%BB%E7%BB%9F-flashing-system}

Flask 的闪存系统(flashing system)用于向用户提供反馈信息,这些反馈信息一般是对用户上一次操作的反馈。

反馈信息是存储在服务器端的,当服务器向客户端返回反馈信息后,这些反馈信息会被服务器端删除。

详细的app.py代码如下:

import time

from flask import Flask, get_flashed_messages, flash

app = Flask(name) app.secret_key = 'some_secret'

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

@app.route('/gen') def gen(): info = 'access at ' + time.time().str() flash(info) return info

@app.route('/show1') def show1(): return get_flashed_messages().str()

@app.route('/show2') def show2(): return get_flashed_messages().str()

if name == 'main': app.run()


赞(2)
未经允许不得转载:工具盒子 » 详细的Python Flask的操作