flask框架之视图处理、请求、响应、异常补获、CBV

前言

这几年一直在it行业里摸爬滚打,一路走来,不少总结了一些python行业里的高频面试,看到大部分初入行的新鲜血液,还在为各样的面试题答案或收录有各种困难问题

于是乎,我自己开发了一款面试宝典,希望能帮到大家,也希望有更多的Python新人真正加入从事到这个行业里,让python火不只是停留在广告上。

微信小程序搜索:Python面试宝典

或可关注原创个人博客:https://lienze.tech

也可关注微信公众号,不定时发送各类有趣猎奇的技术文章:Python编程学习

视图

请求

请求属性

from flask import request

request对象中包含很多可以利用的属性,可以帮助在视图编写时获取有关用户请求部分的数据

request.method # 请求方式,如GET、POST大写字符串

request.args # get请求提交的数据
request.from # post请求提交的数据
request.files # 请求提交的文件

request.values 
'''
是一个列表,包含query及post的全部数据
列表[0]上的是query数据,列表[-1]是post数据
获取其中数据时直接通过key即可,不需要选访问对应索引的字典
如果get与post参数key值相同,可以通过getlist批量获取到全部的,再通过索引区分
'''

假设当前get传递?id=1&name=2,post传递的也是{id:1},那么通过getlist获取,返回结果为一个类似列表的数据结构

其中索引为0的位置上是get传递的数据,索引为1的位置上是post/put提交的数据

request.values.getlist("id") 
# CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('name', '2')]), ImmutableMultiDict([('id', '1')])])
# 返回结果: ['1', '1']

request.cookies # 客户端所带的cookie
request.headers # 请求头
request.path # 不带域名,请求路径
request.full_path 不带域名,带参数的请求路径

request.url 带域名带参数的请求路径
request.base_url 带域名请求路径

数据获取

get

http://127.0.0.1:5000/?id=1

from flask import Flask, request
@app.route('/')
def index():
  	# url中?后面所有的值,最为一个字符串
    print(request.query_string) 
    # 返回ImmutableMultiDict,类似字典,连接查询参数中的?key=value组成的字典{key:value}
    print(request.args) 
		...

返回结果如下所示

b'id=1'
ImmutableMultiDict([('id', '1')])
post/put

如果是form表单提交,form-data格式数据,比如

id : 1
request.form # 获取form表单类型提交的数据
ImmutableMultiDict([('id', '1')])

如果是json格式提交,那么可以通过request.json获取

{
    
    
	"id": 1,
}
request.json # 获取application/json格式提交的数据,处理为一个字典数据
{
    
    'id': '1'} 

文件获取

  • 一个带有 enctype=multipart/form-data 的 标记,标记中含有一个
  • 应用通过请求对象的 files 字典来访问文件
  • 使用文件的 save() 方法把文件永久地保存在文件系统中

记得上传文件的表单要加着属性enctype="multipart/form-data"

request.files["upload_file"] # 获取文件上传

如果希望将这个文件快速保存至本地,那么flask也提供了save方法,可以使上传文件快速保存

from flask import request
from werkzeug.utils import secure_filename

import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 项目根目录
STATIC_DIR = os.path.join(BASE_DIR, 'static') # 静态文件夹位置

@app.route('/upload', methods=['POST'])
def upload_file():
    if request.method == 'POST':
        f = request.files['upload']
        f.save(os.path.join(STATIC_DIR, secure_filename(f.filename))) # 存储

头部token认证

flask默认的头部信息获取通过headers属性即可拿到,如果是拿取定义的Authorization认证信息,最基本的做法如下

request.headers.get("Authorization")

  • 默认的头部认证机制

那么初次之外,flask还支持一套Basic Auth的认证机制,当客户端发送具有Basic前缀,且是base64编码的头部字段时,将会自动对其进行解析

使用默认头部认证方式,客户端的auth值发起要具备如下格式

  1. token前需带有Basic标示
  2. token值通过username及password组成,使用冒号隔开
  3. 通过base64编码

比如组成一个账号为root,密码为123456的头部

base64.b64encode("root:123456".encode())
# cm9vdDoxMjM0NTY=

那么发起的请求头部将是这样

Authorization: Basic cm9vdDoxMjM0NTY=

flask在检测到头部中含有Authorization属性时,并且此时Authorization属性对应的value是具备Basic前缀,那么会自动将其进行解析,并将解析到的username和password存入request.authorization属性中

最后如果Authorization属性合法传递,那么可以通过request.authorization对象轻松获取到username及password

request.authorization
request.authorization.username # root
request.authorization.password # 123456

默认的认证解析部分源码如下

...
if auth_type == b"basic":
    try:
        username, password = base64.b64decode(auth_info).split(b":", 1)
        # 通过冒号进行base64解码后字符串的切分,对应上方组成token的规则
		...
    return Authorization(
        "basic",
        {
    
    
            "username": to_unicode(username, _basic_auth_charset),
            "password": to_unicode(password, _basic_auth_charset),
        },
    )

响应

  • 如果视图返回的是一个响应对象,那么就直接返回它

  • 如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的响应对象

  • 如果返回的是一个字典,那么调用 jsonify 创建一个响应对象,也就是application/json

  • 如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少包含一个项目,且项目应当由 (response, status) 、 (response, headers) 或者 (response, status, headers) 组成。 status 的值会重载状态代码, headers 是一个由额外头部值组成的列表或字典

如果以上都不是,那么 Flask 会假定返回值是一个有效的 WSGI 应用并把它转换为一个响应对象


普通响应

(html字符串, 状态码, 头部信息)

(body, status, headers), (body, status), or (body, headers)

@app.route('/', methods=["GET", "POST"])
def index():
    return ("ABC", 404, {
    
    "Content-Type": "application/json"})

redirect

redirect用作重定向使用,常见的在登陆后的跳转或者权限判断后的跳转工作

@app.route('/')
def index():
    return redirect(url_for("home")) # 重定向至home视图

@app.route('/home', endpoint="home")
def home():
    return 'home'

render_template

返回一个模版,第一个参数是模板的名字,之后的参数是模版传递的上下文,只要你愿意,可以传递无数个

还可以传函数,在模板中调用函数

@app.route("/")
def index():
    return render_template("index.html", double=lambda x : x * 2)

index.html的内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
	{
   
   { double(2) }}
</body>
</html>

make_response

make_response函数生成Response对象,可以对响应进行一些设置后再返回,比如设置cookie

可以传入一个字符串对象,它将被编码为UTF-8并被显示在body中

也可以传入一个字典类型的对象,它将被先变成json格式再返回

也可以传入一个元组,包含两个或者三个元素,分别是body内容,status状态码,headers响应头(字典类型)

from flask import make_response
@app.route("/response")
def response():
    response = make_response("<h1>This response</h1>")
    response.set_cookie("id","1") # 设置cookie
    response.headers["Header"] = "header" # 响应头上放东西
    return response

还可以对返回的响应体进行包裹,获得响应对象,并对该对象进行修改,然后再返回

@app.errorhandler(404)
def not_found(error):
	resp = make_response(render_template('error.html'), 404) # 加工响应体
    resp.headers['X-Something'] = 'A value' # 设置头部
    return resp

abort

abort()函数用于提前退出一个请求,并用指定的错误码返回

参数可以是一个状态码,比如,404;也可以是一个WSGI应用

abort(404)
abort(Response('Hello World'))

jsonify

JSON 格式的响应是常见的,用 Flask 写这样的 API 是很容易上手的,如果从视图返回一个 dict 将会自动转换为一个 JSON 响应

@app.route("/user")
def user():
    return {
    
    
        "username": "zhangsan",
        "image": url_for("static", image_path),
    }

还可以使用flask自带的json处理类jsonify进行json数据处理,并返回,支持Python中可以被json处理的数据类型

通过jsonify返回的数据头部的Content-Type为application/json

app.config['JSON_AS_ASCII'] = False
@app.route('/')
def index():
    return jsonify({
    
    "name": "张三"})

如果使用json模块封装json处理,那么Content-Type为text/html; charset=utf-8

@app.route('/')
def index():
		return json.dumps({
    
    "name": "张三"}, ensure_ascii=False)

注意:如果想正确展示中文,而非通过编码显示,那么要用到如下配置

app.config['JSON_AS_ASCII'] = False # jsonify配置
json.dumps(ensure_ascii=False) # jsom模块

错误捕获

errorhandle可以捕获错误,并且对错误做出响应,返回给用户,必须要在装饰器参数明确捕获的错误码

@app.errorhandler(500)
def error_500(e):
    return "Something Wrong % s" % e

CBV

FBV简单, 小巧, 当不涉及到复杂的逻辑时可以使用FBV

CBV灵活, 为什么说灵活呢?因为, 类的封装, 继承, 多态, 你说灵活不灵活

views.View

views.View是最基本的视图基类,在dispatch_request方法中进行逻辑处理

def login(f): # 测试装饰器
    def wapper(*args, **kwargs):
        print("login wapper")
        return f(*args, **kwargs)
    return wapper
  
class Index(views.View):
	methods = ["GET"] # 请求方式
    decorators = [login] # 请求到达会执行的装饰器方法
    
    def dispatch_request(self):
		return "index"

注册路由

app.add_url_rule("/", view_func=Index.as_view(name="index"))
# as_view的参数name代表当前路由映射视图的路由命名
# 该命名必须提供,否则所有的视图都会叫View这就不对了

MethodView

该基类提供了真正对于请求反射的实现方法,可以类似django的视图进行get、post等请求的映射编写视图

class Index(views.MethodView):
    methods = ["GET"]
    decorators = [login]

    def get(self):
        return "Index"

路由映射是一样的

app.add_url_rule("/", view_func=Index.as_view(name="index"))

猜你喜欢

转载自blog.csdn.net/HeroicLee/article/details/120991309