一. 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() %}
- {{ }} 引用 或 执行
- {% %} 逻辑引用
高级应用
- 传递函数
类似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
- 宏指令(应用不多,可由第一种方法代替)
用于生成标签
{% macro my_input(na,ty) %} #定义宏指令,类似前端定义函数
<input type="{{ ty }}" name="{{ na }}">
{% endmacro %}
{{ my_input("password","password") }}
四. Flask中的session
session是一个公共变量,把它当做字典来用,生命周期默认31天,也具有上下文管理机制,不像Django封装在request对象中.
- Flask 中 session 是需要 secret_key 的
app = Flask(__name__)
app.debug = True
app.secret_key='YHPadkjaksldlkasjdkl' #一般是MD5等方式加密的
secret_key 实际上是用来加密字符串的,如果在实例化的app中没有 secret_key 那么开启session一定会抛异常的
- 使用方法
@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
来源:oschina
链接:https://my.oschina.net/u/4395857/blog/3438274