flask 初识
一、flask 中的 返回值
示例:一个简单的 flask 项目的启动
该框架的返回值主要包括5类( 字符串、重定向、页面、json数据、文件(图片和视频)等 )
from flask import Flask, redirect, render_template,json,jsonify,send_file app = Flask(__name__) @app.route("/") def index(): # return "hello" # 返回字符串直接返回即可 return redirect("/login") # 重定向 @app.route('/login',methods=["POST","GET"]) # 不写methods,默认是GET请求, def home(): return render_template('login.html') # 返回html页面,template设置为 mark derectory @app.route('/json') def jsons(): l = {'name':'cheney'} # return json.dumps(l) # 响应头:Content-Type: text/html; charset=utf-8 () return jsonify(l) # 响应头:Content-Type: application/json(返回json标准的字符串 )两者是响应头的区别,前端能够识别 @app.route('/file') def file(): # return send_file('01.mp4') # send_file(),打开文件并返回文件内容(自动识别文件格式) return send_file('22.png') # 返回的是图片,二进制文件时,背景是特殊颜色 app.run("0.0.0.0",5000,debug=True) # 设置debug=True,修改代码,项目可以不重启,如果里面不写参数,默认是127.0.0.1:5000端口的
二、flask 中的 request
request,是公共变量
from flask import request request.method # 请求方式 'POST' 'GET' request.form # 存放FormData中的数据 to_dict 序列化成字典("username":"chen","password":"123"),表单数据提交的都是formdata类型的 request.args # 获取URL中的数据 to_dict 序列化成字典 (get请求中的参数,问号之后的) request.files # 序列化文件存储 save() request.url # 访问的完整路径 http://127.0.0.1:8000/login 有参数包括参数 ?a=1&b=2 request.path # 路由地址 (/login) request.host # 主机地址 (127.0.0.1:8000) request.values # 获取 FormData and URL中的数据,不要用to_dict,会覆盖 request.json # 如果提交时请求头中的Content-Type:application/json 字典操作 request.data # 如果提交时请求头中的Content-Type 无法被识别 将请求体中的原始数据存放 byte request.cookies # 获取Cookie中的数据 request.headers # 获取请求头
文件的保存:
my_file = request.files.get("my_file") my_file.save(my_file.filename) # 可以用原文件的名字,也可以用自己定义的名字和路径,'./chen',当前路径
三、Jinja2 语法
flask 中的 Jinja2 类似于 django 中的模板语法(template),两者做的事情是一样的,都是将后端传的内容在前端页面进行渲染
不同的是:
Jinjia2 用法类似python,取值符合字典列表的规则
template 用法都是用点 . 取值
1、变量的取值
{{ }}
取值类似字典,{{ stu.name }} 、{{ stu[name] }}、{{ stu.get(name) }} 都可以获取值,django中模板语法只能用 点 取值
2、逻辑代码
{% %}
3、渲染标签,安全标签字符串
标签字符串 | safe
Markup()
4、全局的
@app.template_global()
5、过滤的
@app.template_filter()
6、宏 macro 用处不大,定义函数,了解即可
示例:
后端 ss.py
from flask import Flask, render_template, Markup app = Flask(__name__) tag = "<input type='text' name='username'>" tag = Markup(tag) # 类似于django中的 Marksafe(),这里用了,前端就不用 tag|safe 了 def func1(a, b): return a + b @app.template_global() def func(a, b): # 类似func1,如果多个页面中都要用到func函数,那么就需要每个路由函数都传值函数名,比较麻烦, # 因此使用,template_global()即可,设为全局的 return a + b @app.template_filter() def filter(a, b, c): # 过滤器函数,template_filter(),也是全局的,不需要传值,模板中直接用即可 print(a) return a + b + c @app.route("/") def index(): return render_template("index2.html", tag=tag, func1=func1) # func1不是全局的,需要传值 app.run(debug=True)
前端 index2.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> {{ tag }} {{ func1(3,3) }} {{ func(5,5) }} {{ 10 | filter(2,3) }} {% macro create_input(na,ty) %} {{ na }} : <input type="{{ ty }}" name="{{ na }}"> {% endmacro %} {{ create_input("username","text") }} </body> </html>
四、flask 中的 session(利用装饰器验证登录)
1、装饰器的用法
装饰器主要是用于对某些程序在运行执行做一些处理操作,
示例:利用装饰器,计算程序运行的时间
import time def waibu(func): def neibu(*args, **kwargs): start = time.time() ret = func(*args, **kwargs) end = time.time() print(end - start) return ret return neibu @waibu def func(): for i in range(100000000): continue return "OK" print(func()) # 1.7812395095825195 # OK
2、Flask-Session
session也是公共变量
session是用于验证用户身份信息的,可以在登录的时候添加session,访问其他页面的时候校验用户身份信息。
django:session是存储在服务端的,
flask:session是加密后存储在前端的cookies中的键值对,节省flask的开销,
由于Flask中默认Session 存放位置 - 客户端的Cookies中,加密使用 app.secret_key = "加密字符串" ,加密字符串可以随便写,主要是用于序列化和反序列化 session信息,
- 有人说,session放在前端cookies中,会不完全?
由于在加密的时候,该加密方式是添加了字符串的,再进行加密,而字符串是保存在后端的,因此,别人不知道字符串自然也无法解密
- 请求进入视图函数 带上cookie 将Session从cookie序列化出来 通过secret_key 反序列化成字典
xxx.py
from flask import Flask, redirect, render_template, request, session app = Flask(__name__) app.secret_key = "DragonFire" # 这里一定要给定字符串,进行加密 @app.route("/login", methods=["POST", "GET"]) # 在涉及到其他请求的时候,一定要添加进来,不写则请求不能访问,默认是GET,如果只有GET访问的话可以不写 def login(): if request.method == "GET": return render_template("login.html") if request.form.get("username") == "chen" and request.form.get("password") == "123": session["user"] = request.form.get("username") # 登录成功,将用户信息添加到session中 ,访问其他路由的时候,通过session进行验证即可。 return redirect("/") app.run(debug=True)
login.html

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <form action="" method="post" enctype="multipart/form-data"> 用户名<input type="text" name="username"> 密码<input type="password" name="password"> 文件:<input type="file" name="my_file"> <input type="submit" value="登录"> </form> </body> </html>
3、利用装饰器验证session,进行用户登录
示例:
from flask import Flask, redirect, render_template, request, session app = Flask(__name__) app.secret_key = "DragonFire" @app.route("/login", methods=["POST", "GET"]) # 登录不能加装饰器,验证session def login(): if request.method == "GET": return render_template("login.html") if request.form.get("username") == "chen" and request.form.get("password") == "123": session["user"] = request.form.get("username") print(session['user']) print(11) return redirect("/index") def wai(func): # 验证session信息的装饰器函数 def nei(*args, **kwargs): if session.get("user"): # session取值,不要使用所以["user"]取值,因为不确定时候有键,没有会报key-error错误 ret = func(*args, **kwargs) return ret else: return redirect("/login") return nei @app.route("/",methods=['GET'],endpoint='hello') # 不指定endpoint的函数名,会报错,装饰器不能使用,另外装饰器(@wai)要放在下面 @wai # nei = wai(hello) def hello(): return 'hello' @app.route("/index",methods=['GET'],endpoint='index') @wai # nei = wai(index) def index(): # if not session.get("user"): # 可以再每个函数中进行session身份信息的验证,但是比较麻烦,会有代码的重复 # return redirect("/login") return render_template("index.html") app.run(debug=True)
总结:
1、装饰器函数修饰要放在@app.route() 的下面
2、使用装饰器@wai,没有在@app.route()中指明 endpoint的路由函数,装饰器是不能使用的,会报一下错误
AssertionError: View function mapping is overwriting an existing endpoint function: nei
为什么会出现这种问题?
使用Flask定义URL的时候,如果出现"AssertionError: View function mapping is overwriting an existing endpoint function"这个异常信息,就说明定义了多个同名的视图函数,只需要改成不同的函数名即可。 这是为什么呢? 原来flask中url跟视图函数并不是直接对应的,而是有一个中间者-endpoint。 三者之间的关系是这样的: ``` url---->endpoint---->view_function ``` 它们是一对一的关系,在注册add_url_rule的时候,如果不指定endpoint,那么endpoint就会默认为函数名字,如果同一个endpoint于多个url注册的话,就会发生冲突,从而抛出异常。
3、解决办法就是:在route中指明 endpoint="路由函数名"
方式一:在route中指明 endpoint="路由函数名",上面的示例采用的是该方式
源码中解析:
如果不指定endpoint,那么会默认是传入@app装饰器的原函数,这里也就是@wai 装饰后的函数名 nei,多个函数都装饰的时候就会重复,所以会报错
方式二、利用functools保持原来的函数名