一:安装和初始
1.Flask 安装 + 启动
from flask import Flask
app = Flask(__name__) # 实例化flask对象 # __name__ 多app应用,分区实例在哪个文件中
app.run()
高级启动:
from flask import Flask
app = Flask(__name__)
@app.route("/") # app中的rotue装饰器
def home(): # 视图函数
return "Hello World!"
app.run()
二: Render, Redirect HttpResponse
2.Flask Response
1.HttpResponse("HelloWorld") "HelloWorld" 返回字符串
from flask import render_template 默认存放路径 templates
2.render("模板路径") render_template 返回模板
from flask import redirect 重定向
3.redirect("/")
Flask 中的返回特殊封装 2个
1.jsonify 转换标准JSON格式
响应头中加入 Content-type:application/json
在Flask 1.1.1 版本中 加入了 直接返回字典 可以不再使用jsonify了
2.send_file 发送文件
打开并返回文件内容,
自动识别文件类型,
响应头中加入Content-type:文件类型 # Content-Type: audio/mpeg
ps:当浏览器无法识别Content-type时,会下载文件
# 大的视频文件是 分段式请求
# 打开并返回文件内容,自动识别文件类型,content-type:文件类型
# Ps:
# 浏览器无法识别content-type时,都以下载返回。 识别的话,直接打开
from flask import Flask, render_template, redirect, jsonify, send_file
# Alt + 回车 快速的导入模块
app = Flask(__name__) # 实例化flask对象 # __name__ 多app应用,分区实例在哪个文件中
app.config["DEBUG"] = True # 能够随时更改自动重启,不加的话每次更改代码需要手动重启
@app.route("/") # app中的rotue装饰器
def home(): # 视图函数
# return 1
# 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.
return "home"
@app.route("/index")
def index():
return render_template("index.html")
@app.route("/reback")
def reback():
return redirect('/index')
@app.route("/json")
def my_jsonify():
# return jsonify({"a":1})
return {"k": "v"}
@app.route("/myfile")
def my_file():
# return send_file('1chushi.py')
# return send_file('1.jpg')
return send_file('ss.mp3')
# 传文件
# 不管video还是audio都是显示 Audio
app.run()
三:Request
3.Flask Request
假登录
405 请求方式不被允许 - GET请求可以 POST请求 405 Method Not Allowed
Form表单 - FormData
f orm - 表单
from flask import request 公共对象
1.request.form 获取FormData中的数据 - Form表单
2.request.args # 获取URL中的参数
3.request.files # 获取FormData中的文件数据
print(request.url) # 获取访问路径
print(request.method) # 获取请求方式
print(request.path) # 路由地址 /login
print(request.values) # Form 和 Args 中的数据
# 综合获取 X
print(request.args.get("id")) # 获取URL中的参数
print(request.args["id"]) # 获取URL中的参数
print(request.args.to_dict()) # 获取URL中的参数 转换成 字典
print(request.environ) # 获取请求原始信息
print(request.base_url) # 获取URL头,不包含参数
print(request.json) # 毁三观 1 请求头中 Content-type:application/json 数据序列化 request.json
print(request.data) # 毁三观 2 请求头中 Content-type 不包含 Form or data
print(request.headers) # 请求头中的数据
3.1:request.py
from flask import Flask, render_template, request
import os
app = Flask(__name__)
app.config["DEBUG"] = True # 能够随时更改自动重启,不加的话每次更改代码需要手动重启
@app.route("/login", methods=["POST", "GET"])
def login():
if request.method == "GET":
print(request.url) # 获取访问路径
# request.url: http://127.0.0.1:5000/login
# request.url: http://127.0.0.1:5000/login?id=1
print(request.method) # 获取请求方式
# GET
# GET
print(request.path) # 路由地址 /login
# /login
# /login
print(request.values) # 可以获取URL中的参数 也可以获取 FormData中的数据
# 综合获取 ,可以获取url 和 formdata的数据
# CombinedMultiDict([ImmutableMultiDict([]), ImmutableMultiDict([])])
# CombinedMultiDict([ImmutableMultiDict([('id', '1')]), ImmutableMultiDict([])])
print(request.args)
# ImmutableMultiDict([('id', '1')])
print(request.args.to_dict()) # 获取URL中的参数 转换成 字典
# {}
# {'id': '1'}
print(request.args.get("id")) # 获取URL中的参数
# None 没有参数的时候就是None
# 1
# print(request.args["id"]) # 获取URL中的参数
# 1
# 字典索引取不到值的时候 ,会出现keyerror
print(request.environ) # 获取请求原始信息
# {'wsgi.version': (1, 0), 'wsgi.url_scheme': 'http', 'wsgi.input': <_io.BufferedReader name=1140>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.run_once': False, 'werkzeug.server.shutdown': <function WSGIRequestHandler.make_environ.<locals>.shutdown_server at 0x000001F2C1CD8378>, 'SERVER_SOFTWARE': 'Werkzeug/0.15.4', 'REQUEST_METHOD': 'GET', 'SCRIPT_NAME': '', 'PATH_INFO': '/login', 'QUERY_STRING': '', 'REQUEST_URI': '/login', 'RAW_URI': '/login', 'REMOTE_ADDR': '127.0.0.1', 'REMOTE_PORT': 14611, 'SERVER_NAME': '127.0.0.1', 'SERVER_PORT': '5000', 'SERVER_PROTOCOL': 'HTTP/1.1', 'HTTP_HOST': '127.0.0.1:5000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9,en;q=0.8', 'HTTP_COOKIE': 'sessionid=wnuu61vo39ha2rnhjly8tturem306js3; csrftoken=dBlvd2yERl2dy9Oe7JoPLWer7aaOf35nx83lvoruaY0NOkl3T747KlIo5YwZ7026', 'werkzeug.request': <Request 'http://127.0.0.1:5000/login' [GET]>}
print(request.base_url) # 获取URL头,不包含参数
# http://127.0.0.1:5000/login
print(request.json) # 毁三观 1 请求头中 Content-type:application/json 数据序列化 request.json
# None
print(request.data) # 毁三观 2 请求头中 Content-type 不包含 Form or data
# b''
print(request.headers) # 请求头中的数据
# Host: 127.0.0.1:5000
# Connection: keep-alive
# Cache-Control: max-age=0
# Upgrade-Insecure-Requests: 1
# User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
# Accept-Encoding: gzip, deflate, br
# Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
# Cookie: sessionid=wnuu61vo39ha2rnhjly8tturem306js3; csrftoken=dBlvd2yERl2dy9Oe7JoPLWer7aaOf35nx83lvoruaY0NOkl3T747KlIo5YwZ7026
return render_template("login.html")
if request.method == "POST":
print(request.method)
# POST
print(request.form)
# Multidict 多重字典,得到字典套列表套元组的类型
# ImmutableMultiDict([('username', '123'), ('pwd', '456')])
print(request.form.to_dict())
# {'username': '123', 'pwd': '456'}
print(request.values) # 可以获取URL中的参数 也可以获取 FormData中的数据
# CombinedMultiDict([ImmutableMultiDict([]), ImmutableMultiDict([('username', '123'), ('pwd', '456')])])
print(request.values.to_dict())
# {'username': '123', 'pwd': '456'}
print(request.json) # 毁三观 1 请求头中 Content-type:application/json 数据序列化 request.json
# None
print(request.data) # 毁三观 2 请求头中 Content-type 不包含 Form or data 原始请求体数据
# b''
print(request.headers)
# Host: 127.0.0.1:5000
# Connection: keep-alive
# Content-Length: 235
# Cache-Control: max-age=0
# Origin: http://127.0.0.1:5000
# Upgrade-Insecure-Requests: 1
# Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1BWoxZMCbTbU3Koy
# User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
# Referer: http://127.0.0.1:5000/login
# Accept-Encoding: gzip, deflate, br
# Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
# Cookie: sessionid=wnuu61vo39ha2rnhjly8tturem306js3; csrftoken=dBlvd2yERl2dy9Oe7JoPLWer7aaOf35nx83lvoruaY0NOkl3T747KlIo5YwZ7026
# print(request.files.get("my_file"))
#
# my_file = request.files.get("my_file")
# # fp = os.path.join("templates",my_file.filename)
# my_file.save(my_file.filename)
# 获取文件的数据
print(request.files)
# ImmutableMultiDict([('my_file', <FileStorage: '1.jpg' ('image/jpeg')>)])
# 文件只在File 里显示
# Form中不包含
print(request.files.get("my_file"))
# <FileStorage: '1.jpg' ('image/jpeg')>
my_file = request.files.get("my_file")
# my_file.save(my_file.filename)
# 保存到本地的
# 可以指定路径 用os模块
fq = os.path.join("templates", my_file.filename)
my_file.save(fq)
username = request.form.get("username")
password = request.form["pwd"]
# Get 和索引都能拿到值
if username == "123" and password == "456":
return "登录成功"
else:
return "登录失败"
# 如果包导入的话,if __name__下面不会执行
if __name__ == '__main__':
app.run()
3.2:login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<link rel="stylesheet" href="bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>
<form action="/login" method="post" enctype="multipart/form-data">
用户名: <input type="text " name="username">
密码: <input type="password" name="pwd">
<input type="file" name="my_file">
<input type="submit">
</form>
<script src="jquery-3.4.1.js"></script>
<script>
</script>
</body>
</html>
四:Jinja2和高级用法
4.Jinja2
{{}} 引用 or 执行
{%%} 逻辑语法 if else for
4.1:jinja2.py
from flask import Flask, render_template,request,redirect,Markup
STUDENT = {'name': 'Ivan', 'age': 38, 'gender': '中'}
STUDENT_LIST = [
{'name': 'Sail', 'age': 38, 'gender': '中'},
{'name': 'Ivan', 'age': 73, 'gender': '男'},
{'name': 'VS', 'age': 84, 'gender': '女'}
]
STUDENT_DICT = {
1: {'name': 'Sail', 'age': 38, 'gender': '中'},
2: {'name': 'Ivan', 'age': 73, 'gender': '男'},
3: {'name': 'VS', 'age': 84, 'gender': '女'},
}
app = Flask(__name__)
app.config["DEBUG"] = True
@app.template_global()
# 把ab函数传到前端了
def ab(a,b):
return a+b
@app.route("/jija")
def jija():
my_in = Markup("<input type='text' name='uname'>")
return render_template("jija.html",
stu_info=STUDENT,
stu_list=STUDENT_LIST,
stu_dict=STUDENT_DICT,
m=my_in
)
if __name__ == '__main__':
app.run("127.0.0.1", 9999)
4.2:jinja2.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ stu_info }}
<table border="1px">
<tr>
<td>name</td>
<td>age</td>
<td>gender</td>
</tr>
<tr>
<td>{{ stu_info.name }}</td>
<td>{{ stu_info.get("age") }}</td>
<td>{{ stu_info["gender"] }}</td>
</tr>
</table>
<br/>
{{ stu_list }}
<table border="1px">
<tr>
<td>name</td>
<td>age</td>
<td>gender</td>
</tr>
```
{% for foo in stu_list %}
<tr>
<td>{{ foo.name }}</td>
<td>{{ foo.get("age") }}</td>
<td>{% if foo["gender"] !="男" and foo["gender"] !="女" %}
女
{{ foo["gender"] }}
{% endif %}
</td>
</tr>
{% endfor %}
```
</table>
<br/>
{{ stu_dict }}
<table border="1px">
<tr>
<td>id</td>
<td>name</td>
<td>age</td>
<td>gender</td>
</tr>
<tr>
{% for id,s in stu_dict.items() %}
<td>{{ id }}</td>
<td>{{ s.name }}</td>
<td>{{ s.get("age") }}</td>
<td>{{ s["gender"] }}</td>
</tr>
{% endfor %}
</table>
<br/>
{{ m }}
<br/>
{% macro my_input(na,ty) %}
<input type="{{ ty }}" name="{{ na }}">
{% endmacro %}
{{ my_input("uname","text") }} # macro 需要启动才生产输入框
<br/>
{#{{ ab(1,2) }}#}
</body>
</html>
五:session
5.Flask中的Session 不是三方组件 //Flask-Session
from flask import session
session 交由客户端保管机制
# eyJ1c2VybmFtZSI6IjEyMyJ9.XSVpHA.W0NfiCmW-lsTV0mvQI7mx2mf1Wo
# .eJyrViotTi3KS8xNVbJSMjQyVtKBCxhiiBhhiBhjiJhgiJhiiJhBRWoBMFYkPg.XSVsaA.9merwNdTg3ZkZrdTumYRG7x8x7Y
# .eJyrViotTi3KS8xNVbJSMjQyVtKBCxhiiBhhiBhjiJhgiJhiiJhBRWoBMFYkPg.XSVsvg.6OqcN7CR6nrT2BtE-w1kBAr3xPo
# .eJxNzL0OgCAMBOB36exAoRTjs7jwUzcdNEzGdxckMV1u-e7uhnrJecRdYIG1eqS5pWCB6RccZDGtlQSjIvsRBxtbwZEmN8gZ21czK6JBiamtQhZF_qPAuR-WookH-dQO_WYiPC-8zDp8.XSVtLw.7I-z1bsqiWFln3cipbrVOpEE33g
反序列化机制 -
当客户端发起请求 - request 带上 Cookie - Cookie中有session的加密字符串 - Flask 收到Session加密字符串 - 通过secret_key解密session的加密字符串 - 获得 {username:123}
序列化机制 - 开启session - session["username"] = uname
先创建一个字典 {username:123} 接下来 通过secret_key + 时间戳 + 签名 加密 形成
# eyJ1c2VybmFtZSI6IjEyMyJ9.XSVpHA.W0NfiCmW-lsTV0mvQI7mx2mf1Wo session的加密字符串
5.1:session.py
from flask import Flask, session, request, render_template, redirect
app = Flask(__name__)
app.debug = True
app.secret_key = "adfnaskjfnakjs"
STUDENT = {'name': 'Old', 'age': 38, 'gender': '中'}
STUDENT_LIST = [
{'name': 'Old', 'age': 38, 'gender': '中'},
{'name': 'Boy', 'age': 73, 'gender': '男'},
{'name': 'EDU', 'age': 84, 'gender': '女'}
]
STUDENT_DICT = {
1: {'name': 'Old', 'age': 38, 'gender': '中'},
2: {'name': 'Boy', 'age': 73, 'gender': '男'},
3: {'name': 'EDU', 'age': 84, 'gender': '女'},
}
@app.route("/login", methods=["POST", "GET"])
def login():
if request.method == "GET":
return render_template("login.html")
uname = request.form.get("username")
pwd = request.form.get("pwd")
if uname == '123' and pwd == '123':
session['username'] = uname
return "登陆成功"
else:
return "登录失败"
@app.route("/detail")
def detail():
if session.get("username"):
return render_template("jija.html",
stu_info=STUDENT,
stu_list=STUDENT_LIST,
stu_dict=STUDENT_DICT, )
else:
return redirect("/login")
if __name__ == '__main__':
app.run("127.0.0.1", 9999)
5.2:login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<link rel="stylesheet" href="bootstrap-3.3.7-dist/css/bootstrap.min.css">
</head>
<body>
<form action="/login" method="post" enctype="multipart/form-data">
用户名: <input type="text " name="username">
密码: <input type="password" name="pwd">
<input type="file" name="my_file">
<input type="submit">
</form>
<script src="jquery-3.4.1.js"></script>
<script>
</script>
</body>
</html>