Flask中的Response/Request/session/jinja2/装饰器

て烟熏妆下的殇ゞ 提交于 2020-05-08 07:40:47

一. Response

1.Flask中的HTTPResponse

Content-Type: text/html; charset=utf-8

from flask import Flask

app = Flask(__name__)


@app.route('/') # app中的路由装饰器
def home():
"""
视图函数
:return: 响应(5种)
"""
return 'Hello Flask' # HTTPresponse


app.run()

在Flask 中的HttpResponse 在我们看来其实就是直接返回字符串

2.Flask中的Redirect

from flask import Flask, redirect

app = Flask(__name__)


@app.route('/jump') 
def jump():
return redirect('/')


app.run()

3.Flask 中的 render (render_template)

Content-Type: text/html; charset=utf-8

from flask import Flask,render_template

app = Flask(__name__)

@app.route('/index')
def index():
return render_template('index.html') #渲染HTML模板,返回页面,可以加参数传入前端


app.run()

如果要使用 render_template 返回渲染的模板,请在项目的主目录中加入一个目录 templates.

pycharm提示模板找不到,飘黄,解决办法:右击templates文件夹→Mark Directory as→Template Folder→提示选择模板语言→选择jinja2

以上是Web框架的 Response 三剑客,响应内容均为字符串格式

TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a int.
127.0.0.1 - - [06/Aug/2019 17:01:38] "GET / HTTP/1.1" 500 -
返回错误的数据类型,抛出的异常,可以看到响应返回值可以是string, dict, tuple, Response instance, or WSGI callable

4.send_file()

他的返回值是Response instance ,根据文件编码自动识别文件类型,返回文件内容,Content-type中添加文件类型,即Content-type:text/plain;image/jpeg;等

  • 可识别的Content-type 自动渲染
  • 不可识别的Content-type 会自动下载
from flask import send_file
@app.route('/get_file')
def get_file():
return send_file("1.jpg")

5.jsonify()

返回标准格式的JSON字符串,先序列化JSON的字典,然后Content-type:Application/json

from flask import jsonify
@app.route('/get_json')
def get_json():
return jsonify([1,2,3]) #返回标准json格式字符串,通常在API接口中使用

Flask 1.1.1 版本中,可以直接返回字典格式,无需jsonify

二. Flask中的Request

flask中的request是公共变量,可以被多个线程修改的,但是request有请求上下文管理,保证多线程数据安全.

request.method 获取请求方式 
request.form 获取FormData中的数据 也就是所谓的Form标签 to_dict()
request.args 获取URL中的数据 to_dict()

request.json 请求中 Content-Type:application/json 请求体中的数据 被序列化到 request.json 中 以字典的形式存放
request.data	请求中 Content-Type 中不包含 Form 或 FormData 保留请求体中的原始数据 b""
request.files 获取Form中的文件

request.path	请求路径 路由地址
request.url	访问请求的完整路径包括 url参数
request.host	主机位 127.0.0.1:5000 
request.cookies 字典获取浏览器请求时带上的Cookie

三. jinja2

普通应用

templates语言,更接近python语言,字典可以用索引,get和点取值,甚至可以用python的方法{% for skey,svalue in stu_d.items() %}

  • {{ }} 引用 或 执行
  • {% %} 逻辑引用

高级应用

  1. 传递函数

类似Django的simple_tag,后端定义函数生成标签,传递该函数到前端引用

模板中有,

{{ my_input("username","text") }}

在视图文件中,定义如下函数,并通过render传入前端

@app.template_global() #增加此装饰器后,该函数变为模板全局引用,不需要再render传递
def my_input(na,ty):
s = f"<input type='{ty}' value='{na}'>" #此处为字符串格式化
return Markup(s) # 需要导入,作用同mark_safe
  1. 宏指令(应用不多,可由第一种方法代替)

用于生成标签

{% macro my_input(na,ty) %} #定义宏指令,类似前端定义函数
<input type="{{ ty }}" name="{{ na }}">
{% endmacro %}

{{ my_input("password","password") }}

四. Flask中的session

session是一个公共变量,把它当做字典来用,生命周期默认31天,也具有上下文管理机制,不像Django封装在request对象中.

  1. Flask 中 session 是需要 secret_key 的
app = Flask(__name__)
app.debug = True
app.secret_key='YHPadkjaksldlkasjdkl' #一般是MD5等方式加密的

secret_key 实际上是用来加密字符串的,如果在实例化的app中没有 secret_key 那么开启session一定会抛异常的

  1. 使用方法
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
if request.form["username"] == USER["username"] and request.form["password"] == USER["password"]:
session["user"] = USER["username"]
return redirect("/student_list")
return render_template("login.html", msg="用户名密码错误")

return render_template("login.html", msg=None) # 如果前端Jinja2模板中使用了msg,这里就算是传递None也要出现msg

session["user"] = USER["username"] 这样用就代表这个请求带上来的session中保存了一个user=name,那么session和请求怎么对应的呢?看到请求上下文就懂了.

Flask中的session采取交由客户端保管机制.

cookies 中 session 存储的是通过 secret_key 序列化加密后的字符串,

每次访问浏览器携带session,当取session中的值的时候,通过secret_key 再反序列化出之前存储的信息.

不建议在原生session中加入过多的key,影响效率

五. 校验装饰器使用

多层装饰器

多个装饰器装饰同一个函数时,从下自上执行

def wrapper(func):  # func = home
    def inner(*args, **kwargs):
        # 校验session
        if session.get("username"):
            ret = func(*args, **kwargs)  # func = home
            return ret
        else:
            return redirect("/login")
    return inner

@app.route('/index') # 
@wrapper  # 装饰器从下向上执行,应该先校验登录状态,然后再匹配路由执行视图
def index():
    return render_template('index.html', student_d=STUDENT_DICT)

# 执行过程:将index传入wrapper,返回一个包含了index的函数inner,然后将inner传入app.route装饰器进行装饰.

同一装饰器装饰多个函数

方法一:基于flask出现该错误的原因

由上一话题可知,wrapper装饰器返回的函数名字均为inner,进到路由装饰器后

def wrapper(func): 
    def inner(*args, **kwargs):
        # 校验session
        if session.get("username"):
            ret = func(*args, **kwargs)  # func = home
            return ret
        else:
            return redirect("/login")
    return inner

@app.route('/index',endpoint='index') # 校验多个装饰器要加endpoint,类似别名
@wrapper 
def index():
	return render_template('index.html', student_d=STUDENT_DICT)


@app.route('/detail',endpoint='detail') 
@wrapper
def detail():
	id = int(request.args.get('id'))
	student_d = {}
	student_d[id] = STUDENT_DICT[id]
	return render_template('detail.html', student_d=student_d)

方式二:基于装饰器原理

from functools import wraps 
def wrapper(func):
    @wraps(func) # 保存原来函数的所有属性,包括文件名
    def inner(*args, **kwargs):
        # 校验session
        if session.get("username"):
            ret = func(*args, **kwargs)  # func = home
            return ret
        else:
            return redirect("/login")
    return inner # 用此装饰器后inner.__name__==func__name__==home或detail
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!