flask json传输失败_带你入门Flask

0|1一. Python 现阶段三大主流Web框架 Django Tornado Flask 对比
1.Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架
2.Tornado 主要特点是原生异步非阻塞,在IO密集型应用和多任务处理上占据绝对性的优势,属于专注型框架
3.Flask 主要特点小而轻,原生组件几乎为0, 三方提供的组件请参考Django 非常全面,属于短小精悍型框架
Django 通常用于大型Web应用由于内置组件足够强大所以使用Django开发可以一气呵成
Tornado 通常用于API后端应用,游戏服务后台,其内部实现的异步非阻塞真是稳得一批
Flask 通常应用于小型应用和快速构建应用,其强大的三方库,足以支撑一个大型的Web应用
Django 优点是大而全,缺点也就暴露出来了,这么多的资源一次性全部加载,肯定会造成一部分的资源浪费
Tornado 优点是异步,缺点是干净,连个Session都不支持
Flask 优点是精悍简单,缺点可能就是你不会!0|1Flask打印我们万能的HelloWorld
pip install Flask

6f7d94771d318d3dd8dc9bb1a128c930.png

0|1Flask中的HttpResponse Render RedirectHttpResponse

e61fd8934ac00b10589ea7826a89b7d1.png


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

1c2cb18f9e27ec809d03470d2f34e756.png

render(render_template)
Flask里面的render对应的是render_template

5d3a6bac64377c026fc3cd3095023479.png


后面直接跟html文件名,只要改html文件建在同目录下的templates文件夹中,会自动匹配

f98dd93dedfcf9d2d443bbdfbf6f0d28.png

0|1Flask处理函数返回值的其他类型方法jsonify
类似与Django里面的JsonResponse,返回json序列化后的数据,在Flask项目中需要对数据进行序列化传输时,用这个比json.dumps要好很多send_file
返回文件类型的数据(图片、视频等)

fb33376641806effe370230c9b8532d9.png

注意注意:一定要注意,用jsonify序列化数据时,数据格式必选严格满足json格式,单引号的字符串也不行,它不像json在序列化时会将单引号变成单引号。而它不行!0|1Flask中的request对象

009d2707b9779c9f283fd561195c7b9a.png


methods=["POST"] 代表这个url地址对应的视图函数只允许 POST 请求,是个列表也就是意味着可以允许多重请求方式,例如GET之类的 request.method
与Django里面的方法一致,获取本次请求的请求方式request.form
获取前端用form表单提交过来的数据
print(request.form) # ImmutableMultiDict([('user', 'Oldboy'), ('pwd', 'DragonFire')]) # ImmutableMultiDict 它看起来像是的Dict 就用Dict的方法取值试一下吧 print(request.form["user"]) # Oldboy print(request.form.get("pwd")) # DragonFire # 看来全部才对了, ImmutableMultiDict 似乎就是个字典,再来玩一玩它 print(list(request.form.keys())) # ['user', 'pwd'] 看来是又才对了 request.args
获取url中传递过来的所有参数值

c67b4248d791fabaa1f8f2cd4c82668a.png


然后会在控制台中看到 ImmutableMultiDict([('id', '1'), ('age', '20')]),获取到的数据直接当作字典进行操作即可
request.args 与 request.form 的区别就是:
  request.args 是获取url中的参数
  request.form 是获取form表单中的参数request.values
只要是参数,无论是post过来的还是get过来我全部接受
print(request.values) # CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('age', '20')]), ImmutableMultiDict([('user', 'Oldboy'), ('pwd', 'DragonFire')])]) print(request.values.get("id")) # 1 print(request.values["user"]) # Oldboy # 这回喜欢直接操作字典的小伙伴们有惊喜了! to_dict() 方法可以直接将我们的参数全部转为字典形式 print(request.values.to_dict()) # {'user': 'Oldboy', 'pwd': 'DragonFire', 'id': '1', 'age': '20'}
同样获取到的数据直接当成一个大字典进行操作即可注意啦!注意啦!
# 注意这里的坑来啦! 坑来啦! # 如果url和form中的Key重名的话,form中的同名的key中value会被url中的value覆盖 # http://127.0.0.1:5000/req?id=1&user=20 print(request.values.to_dict()) # {'user': 20 'pwd': 'DragonFire', 'id': '1'} request.headres
用来获取本次请求的请求头

获取请求头request.data
没有加请求头的数据都可以在这个里面找到,并且是bytes类型request.files
如果遇到文件上传的话,request.files 里面存的是你上传的文件,但是 Flask 在这个文件的操作中加了一定的封装,让操作变得极为简单
my_file = request.files["file"] my_file.save("test.txt") # 保存文件,里面可以写完整路径+文件名
这样我们就成功的保存了一个名叫 "test.txt" 的文件了,操作还是很简单的 request.获取各种路径
# 获取当前的url路径 print(request.path)# /req # 当前url路径的上一级路径 print(request.script_root) # # 当前url的全部路径 print(request.url) # http://127.0.0.1:5000/req # 当前url的路径的上一级全部路径 print(request.url_root ) # http://127.0.0.1:5000/ request.json
如果在请求中写入了 "application/json" 使用 request.json 则返回json解析数据, 否则返回 None0|1Flask中的模板语言Jinja2以及render_template的深度用法
Flask对Jinja2稍微做了一点点的加工修饰
针对传入是字典的数据对象操作
<tr> <td>{{ student.name }}</td> <td>{{ student["age"] }}</td> <td>{{ student.get("gender") }}</td> </tr>
针对传入是列表套字典对象的操作
STUDENT_LIST = [ {'name': 'Old', 'age': 38, 'gender': '中'}, {'name': 'Boy', 'age': 73, 'gender': '男'}, {'name': 'EDU', 'age': 84, 'gender': '女'} ]
<tr> <td>{{ foo }}</td> <td>{{ foo.name }}</td> <td>{{ foo.get("age") }}</td> <td>{{ foo["gender"] }}</td> </tr>
针对传入的是{1:{}}这种大字典类型
STUDENT_DICT = { 1: {'name': 'Old', 'age': 38, 'gender': '中'}, 2: {'name': 'Boy', 'age': 73, 'gender': '男'}, 3: {'name': 'EDU', 'age': 84, 'gender': '女'}, }
<tr> <td>{{ foo }}</td> <td>{{ student.get(foo).name }}</td> <td>{{ student[foo].get("age") }}</td> <td>{{ student[foo]["gender"] }}</td> </tr>
后端传入多个数据类型,采用赋值语句传值方式,一个一个传!
@app.route("/allstudent") def all_student(): return render_template("all_student.html", student=STUDENT , student_list = STUDENT_LIST, student_dict= STUDENT_DICT)0|1Jinja2 的高阶用法safe(前端入手)
将你写的html代码直接渲染不转译Markup(后端入手)

View Code
类似于Django里面的mark_safe()模板中执行函数
先在后端中定义函数,类似于Django中的sample_tag/inclusion_tag等
from flask import Flask from flask import render_template from flask import Markup # 导入 flask 中的 Markup 模块 app = Flask(__name__) #定义一个函数,把它传递给前端 def a_b_sum(a,b): return a+b @app.route("/") def index(): return render_template("index.html", tag=a_b_sum) app.run("0.0.0.0", 5000, debug=True)
通过tag参数将我们写的函数传递到前端页面
前端代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ tag }} <br> {{ tag(99,1) }} </body> </html>

331068a6184e0eec36d7ecbaad0a4f7d.png


看到结果就是,函数加()执行得到结果
还可以定义全局函数template_global(),无需后端传递给前端,Jinja2直接就可以执行的函数
对于这种处理函数,还可以有一种偏函数template_filter()的应用,管道符前面的值作为函数的第一个参数传入函数中
from flask import Flask from flask import render_template from flask import Markup # 导入 flask 中的 Markup 模块 app = Flask(__name__) @app.template_global() # 定义全局模板函数 def a_b_sum(a, b): return a + b @app.template_filter() # 定义全局模板函数 def a_b_c_sum(a, b, c): return a + b + c @app.route("/") def index(): return render_template("index.html", tag="") app.run("0.0.0.0", 5000, debug=True)
前端代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ a_b_sum(99,1) }} <br> {{ 1 | a_b_c_sum(197,2) }} </body> </html>
管道符前面也可以是一个函数,会将函数的返回值作为后面函数的第一个参数

9457ac48c156c3a1f263af770c19e051.png

Jinja2模板复用 block
跟Django里面的block模板语言一模一样,还有模板继承语言extends,模板应用语言include。跟Django里面的是一模一样的用法,这里不做赘述0|1Jinja2模板语言中的宏定义
简单的说就是在前端页面中直接定义函数,并直接在前端调用执行定义的函数
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Welcome OldboyEDU</h1> {% macro type_text(name,type) %} <input type="{{ type }}" name="{{ name }}" value="{{ name }}"> {% endmacro %} <h2>在下方是使用宏来生成input标签</h2> {{ type_text("one","text") }} {{ type_text("two","text") }} </body> </html>
宏定义一般情况下很少应用到,但是要知道有这么个概念,起码能吹个牛逼见识广博!0|1Flask实战
需求:
1. 用户名: oldboy 密码: oldboy123
2. 用户登录成功之后跳转到列表页面
3. 失败有消息提示,重新登录
4.点击学生名称之后,可以看到学生的详细信息0|1Flask中的内置Session
Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪
1. Flask 中 session 是需要 secret_key 的(前提条件必须满足!)
from flask import session app = Flask(__name__) app.secret_key = "session_key"
secret_key 实际上是用来加密字符串的,如果在实例化的app中没有 secret_key 那么开启session一定会抛异常的
2. 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.get("user")中拿到设置的值
3. 怎么用 session 进行验证呢?
@app.route("/student_list") def student(): if session.get("user"): return render_template("student_list.html", student=STUDENT_DICT) return redirect("/login")0|1Flask中的路由系统
Flask中的路由系统其实我们并不陌生了,从一开始到现在都一直在应用
@app.route("/",methods=["GET","POST"])1. @app.route() 装饰器中的参数
methods : 当前 url 地址,允许访问的请求方式(当前装饰的视图函数支持的请求方式)
@app.route("/info", methods=["GET", "POST"]) def student_info(): stu_id = int(request.args["id"]) return f"Hello Old boy {stu_id}" # Python3.6的新特性 f"{变量名}"endpoint : 反向url地址,默认为视图函数名 (url_for)
from flask import url_for @app.route("/info", methods=["GET", "POST"], endpoint="r_info") def student_info(): print(url_for("r_info")) # /info stu_id = int(request.args["id"]) return f"Hello Old boy {stu_id}" # Python3.6的新特性 f"{变量名}"
对比Django里面的url反向解析,这里相当于路由解析url
defaults : 视图函数的参数默认值{"nid":1}

不常用
strict_slashes : url地址结尾符"/"的控制 False : 无论结尾 "/" 是否存在均可以访问 , True : 结尾必须不能是 "/",这一点不像Django会帮我们自动补全/
# 访问地址 : /info @app.route("/info", strict_slashes=True) def student_info(): return "Hello Old boy info" # 访问地址 : /infos or /infos/ @app.route("/infos", strict_slashes=False) def student_infos(): return "Hello Old boy infos"
redirect_to : url地址重定向
需要注意的是这里的重定向并不是我们之前接触到那种先访问出一个页面,然后再跳转,而是直接在后端内部直接给你做重定向,可以称为内重定向。举个例子,相当于我有一个网站已经投入使用很久了,用户都将网站的地址收藏了,这个时候我需要扩展网站功能和修改部分功能,这些新功能对应的地址用户有又不知道,这个时候就可以在后端直接用上内重定向的方式,让用户访问的url在我们的服务器内部直接给他重定向到我们新的url地址中
# 访问地址 : /info 浏览器跳转至 /infos @app.route("/info", strict_slashes=True, redirect_to="/infos") def student_info(): return "Hello Old boy info" @app.route("/infos", strict_slashes=False) def student_infos(): return "Hello Old boy infos"
subdomain : 子域名前缀 subdomian="DragonFire" 这样写可以得到 http://DragonFire.oldboyedu.com 前提是app.config["SERVER_NAME"] = "http://oldboyedu.com"
app.config["SERVER_NAME"] = "http://oldboy.com" @app.route("/info",subdomain="DragonFire") def student_info(): return "Hello Old boy info" # 访问地址为: http://DragonFire.oldboy.com/info
对于初始化配置,我们需要知道的几种不同的配置方式:
app.config.from_object("setting.FlaskSetting")
app.DEBUG = True 开启Debug模式,该完代码不用手动重启
app.SECRET_KEY = "xxxxx" 开启session必备参数
app.config['DEBUG']=True
app.run(debug=True)
2.动态参数路由:
from flask import url_for # 访问地址 : http://127.0.0.1:5000/info/1 @app.route("/info/<int:nid>", methods=["GET", "POST"], endpoint="r_info") def student_info(nid): print(url_for("r_info",nid=2)) # /info/2 return f"Hello Old boy {nid}" # Python3.6的新特性 f"{变量名}"
<int:nid> 就是在url后定义一个参数接收,并且要是int类型,也可不加限制
但是这种动态参数路由,在url_for的时候,一定要将动态参数名+参数值添加进去,否则会抛出参数错误的异常
0|1Flask实例化参数及配置
from flask import Flask app = Flask(__name__) # type:Flask app.config["DEBUG"] = True
这句 app.config["DEBUG"] = True 可以实现的功能可刺激了
代码只要发生改动,自动重启Flask程序(app.run)
在控制台打印的信息非常全面
以上两个功能就是传说中的 DEBUG 模式(调试模式)
Flask的配置就是在 app.config 中添加一个键值对,但是你存进去的键必须是config中应该存在的,如果不再存在的话,它会默认无用,就这么放着
config中有多少有用的key 呢?

配置参数大全
修改配置的方式大约是两种
1.直接对app.config进行修改
app.config["DEBUG"] = True
2.使用类的方式导入
首先要有一个settings.py的文件
class FlaskSetting: DEBUG = True SECRET_KEY = "DragonFire"
然后我们在Flask的启动文件中就可以这么写
from flask import Flask app = Flask(__name__) # type:Flask app.config.from_object("settings.FlaskSetting")
它会自动对字符串路径进行处理并导入,相当于importlibFlask实例化时候参数配置
static_folder = 'static', # 静态文件目录的路径 默认当前项目中的static目录 static_host = None, # 远程静态文件所用的Host地址,默认为空 static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用 # host_matching是否开启host主机位匹配,是要与static_host一起使用,如果配置了static_host, 则必须赋值为True # 这里要说明一下,@app.route("/",host="localhost:5000") 就必须要这样写 # host="localhost:5000" 如果主机头不是 localhost:5000 则无法通过当前的路由 host_matching = False, # 如果不是特别需要的话,慎用,否则所有的route 都需要host=""的参数 subdomain_matching = False, # 理论上来说是用来限制SERVER_NAME子域名的,但是目前还没有感觉出来区别在哪里 template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录 instance_path = None, # 指向另一个Flask实例的路径 instance_relative_config = False # 是否加载另一个实例的配置 root_path = None # 主模块所在的目录的绝对路径,默认项目目录需要我们记住的有:
static_folder = 'static', # 静态文件目录的路径 默认当前项目中的static目录 static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用 template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录
这三个参数在后面的Flask蓝图会起到很大的作用0|1Flask中的蓝图(Blueprint)
Flask的蓝图,你可以看成是一个个小的组件,分别能够实现部分功能,在我的主运行文件中只需要将这些蓝图全部注册进来,就可以将这些分散的功能组合成一个整体,这非常符合实际开发需求,十个人可以同时开发不同的功能,最后直接统一注册整合即可拼成“真正的伟大蓝图”1.初识Flask蓝图(blueprint)

fc1b73cb0de7bbca2a7cf08546584abb.png

b8330b8b5b134b31e3415dc3f422e426.png


注册蓝图的时候,可以给某个蓝图再添加一个url前缀

9afad1cd43a323fbb0196dfb32b900e4.png

1|0Flask中的before_request,after_request
我们现在有一个 Flask 程序其中有3个路由和视图函数,如下:

小程序
如果登陆了,就可以访问 index 和 home 页面,如果没登录就跳转到 login 登录
要怎么解决呢, session 对, 用 session 除了 Login 函数之外的所有函数里面全校验 session 是否登录了
太麻烦了,现在咱们只有3个函数,如果成百上千个怎么整啊
装饰器,对没错,装饰器是一个很好的方案,但是啊,我现在还是成败上千个函数,我要在每一个函数定义的时候加上@装饰器,还是很麻烦
那么就引出了我们要学习的第一个知识点:1|11.@app.before_request 在请求(request)之前做出响应

解决所有问题
@app.before_request 也是一个装饰器,他所装饰的函数,都会在请求进入视图函数之前执行
request.path 是来读取当前的url地址如果是 /login 就允许直接通过 return None 你可以理解成通过放行
校验session中是否有user 如果没有的话,证明没有登录,所以毫不留情的 redirect("/login") 跳转登录页面
还有一个要提的 @app.before_first_request 它与 @app.before_request 极为相似或者说是一模一样,只不过它只会被执行一次
看到这里,学过Django的小伙伴们应该有一种似曾相似的感觉,就是这个方法特别像Django里面的中间件process_request方法~~~1|22. @app.after_request 在响应(response)之前做出响应
@app.after_request def foot_log(environ): if request.path != "/login": print("有客人访问了",request.path) return environ
这个则类似于Django里面的process_response方法1|33.@app.errorhandler(状态码)自动捕获状态码做出相应操作

f1487d14d87af6d1ca6234a79734f6b9.png


函数接收的args参数就是原始的报错信息
404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.总结
如果我们在Flask中定义了还几个before_request和after_request装饰函数,如果在经历第一个before_request函数后就被拦截下来,那么如果是Django的中间件则会直接找到同一位置上的process_response去执行返回,而Flask中则是要走所有的after_request方法,无论你是在哪个before_request方法上被拦截的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值