Flask
环境
python3.6
pip install flask
创建最简单的flask项目
from flask import Flask
app = Flask(__name__)
@app.route("/index")
def index():
return "测试index"
app.run()#
#app.run("0.0.0.0",5000,debug=True)
返回的是类似于django的HttpResponses
redirect重定向(标识302)
@app.route("/login")
def login():
return render_template('login.html')
@app.route("/detail")
def detail():
return redirect('/login')
返回页面
render_template(“page.html”)
“GET /detail HTTP/1.1” 302 -
“GET /login HTTP/1.1” 200 -
返回的类型
1 直接返回字符串
可以返回状态码
@app.route(’/testresponse’, methods=[‘GET’, ‘POST’])
def testresponse():
return "xxxxxxxx", 4002 响应Response对象
利用make_reponse()函数接受字符串和错误码,返回一个Response对象,利用这种方法,不但可以成功处理请求,还可以进一步设置响应,如设置cookie等等
from flask import make_response
@app.route(’/testresponse’, methods=[‘GET’, ‘POST’])
def testresponse():
print type( request.cookies )
if request.cookies and request.cookies.get('hyman'):
response=make_response('cookies has been set!')
else:
response=make_response('set cookies!')
response.set_cookie('hyman','123')
return response
3 返回重定向类型redirect
@app.route(’/testresponse’, methods=[‘GET’, ‘POST’])
def testresponse():
return redirect('http://www.baidu.com')4 返回处理错误码
from flask import abort
@app.route(’/testresponse’, methods=[‘GET’, ‘POST’])
def testresponse():
abort(404)
登录视图
@app.route("/login",methods=["GET","POST"])
def login():
if request.method =="GET":
return render_template('login.html')
else:
username = request.form.get("username")
password = request.form.get("password")
args = request.form.to_dict()
print(args)
print(username, password)
return redirect("index")
值的存放
formdata存放在request.form中
parms的参数存放在request.args中
简陋的登录视图
(route中配置methods=[“GET”,“POST”]),默认是只有GET的,建议定义可迭代对象,(列表或者元祖)
form flask import request
@app.route("/login",methods=["GET","POST"])
def login():
if request.method =="GET":
return render_template('login.html')
else:
username = request.form.get("username")
password = request.form.get("password")
formdata = request.form.to_dict()
print(formdata)
print(username, password)
return redirect("index")
send_file
这个函数返回的数据会把数据直接渲染到页面上例如pdf,mp3,图片等
jsonify
返回json格式的数据
请求方式
解释一个 @app.route("/req",methods=[“POST”]) :
methods=[“POST”] 代表这个url地址只允许 POST 请求,是个列表也就是意味着可以允许多重请求方式,例如GET之类的
1.request.method 之 肯定知道前端用什么方式提交的
Flask 的 request 中给我们提供了一个 method 属性里面保存的就是前端的请求的方式
print(request.method) # POST 看来可以使用这种方式来验证请求方式了
2.request.form 之 拿他来举例的话再好不过了
Form表单中传递过来的值 使用 request.form 中拿到
print(request.form) # ImmutableMultiDict([('user', 'bigc'), ('pwd', 'DragonFire')])
# ImmutableMultiDict 它看起来像是的Dict 就用Dict的方法取值试一下吧
print(request.form["user"]) # bigc
print(request.form.get("pwd")) # DragonFire
# 看来全部才对了, ImmutableMultiDict 似乎就是个字典,再来玩一玩它
print(list(request.form.keys())) # ['user', 'pwd'] 看来是又才对了
#如果以上所有的方法你都觉得用的不爽的话
req_dict = dict(request.form)
print(req_dict) # 如果你觉得用字典更爽的话,也可以转成字典操作(这里有坑)
3.request.args 之 你能看见的Url参数全在里面
request.args 中保存的是url中传递的参数
先把后端请求代码改动一下:
from flask import Flask,request
app=Flask(__name__)
@app.route("/test_agrs", methods=["GET","POST"])
def test_agrs():
print(request.args)
return "test is ok"
app.run()
ImmutableMultiDict([(‘id’, ‘101’), (‘age’, ‘18’)])
request.args 与 request.form 的区别就是:
request.args 是获取url中的参数
request.form 是获取form表单中的参数
4.request.values 之 只要是个参数我都要
from flask import Flask,request,render_template
app=Flask(__name__)
@app.route("/login", methods=["GET","POST"])
def login():
if request.method=="GET":
return render_template("login.html")
else:
print(request.values)
print(request.args)
print(
request.values) # CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('age', '18')]), ImmutableMultiDict([('username', 'bigc'), ('password', '123')])])
print(request.values.get("id")) # 1
print(request.values["username"]) # bigc
# 这回喜欢直接操作字典的小伙伴们有惊喜了! to_dict() 方法可以直接将我们的参数全部转为字典形式
print(request.values.to_dict()) # {'username': 'bigc', 'password': '123', 'id': '1', 'age': '18'}
return "ok"
app.run()
这是让我们在使用form表单提交的同时使用url参数提交
request.values) # CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('age', '18')]), ImmutableMultiDict([('username', 'bigc'), ('password', '123')])])
print(request.values.get("id")) # 1
print(request.values["username"]) # bigc
# 这回喜欢直接操作字典的小伙伴们有惊喜了! to_dict() 方法可以直接将我们的参数全部转为字典形式
print(request.values.to_dict()) # {'username': 'bigc', 'password': '123', 'id': '1', 'age': '18'}
return "ok"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/login?id=1&age=18&username=test
#form中填写的是bigc
print(request.values.to_dict()) # {'username': 'test', 'password': '123', 'id': '1', 'age': '18'}
5.request.cookies 之 存在浏览器端的字符串儿也会一起带过来
前提是你要开启浏览器的 cookies
request.cookies 是将cookies中信息读取出来
6.request.headres 之 请求头中的秘密
用来获取本次请求的请求头
print(type(request.headers))
"""
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:5000/home
Content-Type: application/x-www-form-urlencoded
Content-Length: 26
Cookie: csrftoken=vDIozqveCEfArdYXlM6goHVlSQEn7h4bDygNphL2Feas60DiM2di0jlqKfxo7xhA
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
"""
7.request.data 之 如果处理不了(content-type的类型不对的话,就把流信息(b"")保存起来)的就变成字符串儿存在data里面
你一定要知道 request 是基于 mimetype 进行处理的
mimetype的类型 以及 字符串儿 : http://www.w3school.com.cn/media/media_mimeref.asp
如果不属于上述类型的描述,request就会将无法处理的参数转为Json存入到 data 中
其实我们可以将 request.data , json.loads 同样可以拿到里面的参数
上传文件
8.request.files 之 给我一个文件我帮你保管
如果遇到文件上传的话,request.files 里面存的是你上传的文件,但是 Flask 在这个文件的操作中加了一定的封装,让操作变得极为简单
首先改下前端代码:
<h1>欢迎来到文件上传中心</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="提交">
</form>
后端这样写
@app.route("/upload", methods=["GET", "POST"])
def upload():
if request.method == "GET":
return render_template("upload.html")
elif request.method == "POST":
print(request.files)
print(request.files["file"],type(request.files["file"]),)
my_file = request.files["file"]
my_file.save("hello.txt")
return "thanks"
app.run()
print(request.files) # ImmutableMultiDict([('file', <FileStorage: 'DragonFire.txt' ('text/plain')>)])
print(request.files["file"]) # <FileStorage: 'DragonFire.txt' ('text/plain')>
my_file = request.files["file"]
my_file.save("hello.txt") # 保存文件,里面可以写完整路径+文件名
这样我们就成功的保存了一个名叫 “hello.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 之 前提你得告诉是json
如果在请求中写入了 “application/json” 使用 request.json 则返回json解析数据, 否则返回 None
模板渲染
HTML模板渲染是每个Web框架中都必须有的,至于render_template的具体用法,留个悬念,往后看
注意: 如果要使用 render_template 返回渲染的模板,请在项目的主目录中加入一个目录 templates
(顺便提一下,在pycharm编辑器中 可以使用右键mark as template folder)
返回HTML模板:使用“from flask import render_template”,在函数中传入相对于文件夹“templates”HTML模板路径名称字符串即可(默认模板路径),flask会自动到项目根目录的“templates”文件夹(创建flask项目时,PyCharm会自动创建两个空文件夹,其中一个就是“templates”)下寻找对应的HTML文件。
- 默认模板路径:项目根目录下的templates文件夹。
- 自定义模板路径:如果不想使用默认的模板路径,即项目根目录的templates文件夹,可以在实例化flask时指定参数template_folder的值,以指定默认模板的路径。
- 模板传参:如果需要给HTML模板传参,则在“render_template”中使用变量名或字典进行传参即可(在Python2中,如果涉及中文,需要使用Unicode字符串)。
Jinja2
{{}} 取值,执行函数
{%%} 逻辑代码 if for
Markup("标签字符串")
@app.template_global()
@app.template_filter()
{{ func(78,56) | func2(78) }}
宏指令
{% macro func_mac(tp,na) %}
<input type="{{ tp }}" name="{{ na }}">
{% endmacro %}
{{ func_mac('text','username') }}
{{ func_mac('password','pwd') }}
实例for循环和if判断
后端
STUDENT = {'name': 'bigc', 'age': 18, 'gender': '中'},
@app.route("/index")
def index():
return render_template('index.html',stu=STUDENT)
前端
<h1>这里是首页</h1>
{{ stu }}
<table border="1px">
<thead>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
</thead>
<tbody>
<tr>
{% for s in stu %}
<td>{{ s.name }}</td>
<td>{{ s.get("age") }}</td>
<td>{% if s.get("gender")=="中" %}
男
{% else %}
{{ s.get("gender") }}
{% endif %}
</td>
{% endfor %}
</tr>
</tbody>
</table>
结果
markupsaf后端控制生成标签代码
@app.route("/test")
def test():
mylable=' <input type="file" name="file">'
return render_template('test.html',mylable=mylable)
app.run(debug=True)
方法一:前端加|safe即可
<body>
{{ mylable |safe }}
</body>
或者后端使用marksafe
from flask import Flask,render_template,Markup
@app.route("/test")
def test():
mylable=' <input type="file" name="file">'
new_lable=Markup(mylable)
return render_template('test.html',mylable1=new_lable)
前端
{{ mylable1 }}
<h1>测试</h1>
Markup(“标签字符串”)
template_global(全局)
@app.template_global()
@app.template_global()
def func(a,b):
return a*b这样的话 相当于全局都传了func,都可以调用
测试 在某个页面中使用func的功能
{{func(2,3)}}
页面上能出6
@app.route("/test")
def test():
mylable=' <input type="file" name="file">'
new_lable=Markup(mylable)
return render_template('test.html',mylable1=new_lable,my_add =add_func)#这里相当于是指给这个页面传递函数
@app.template_global()
def test_func(a,b):
return a*b
def add_func(a,b):
return a+b
template_filter(全局)
@app.template_filter()
{{ func(78,56) | func2(78) }}
也可以过滤某些字符
from flask import Flask, render_template
#后端
app = Flask(__name__)
@app.route('/')
def index():
content = {
"name": "blue",
"txt": "hello python,python wolrd python!"
}
return render_template("test_filter.html", **content)
#template_filter:可理解过模板过滤
#my_cut为过滤器的名字
@app.template_filter("my_cut")
def cut(value):
value = value.replace("python", "")
return value
if __name__ == "__main__":
app.run(debug=True)
前端
<body>
<h3>{{ txt|my_cut }}</h3>
</body
没替换之前
{{ txt}}
替换之后的结果
{{ txt|my_cut }}
模板的继承
s1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
我是S1的内容
以下是特殊内容
{% block content %}
{% endblock %}
</body>
</html>
s2.html
{% extends "s1.html" %}
{% block content %}
我是S2
{% endblock %}
s3.html
macro定义html标签,传参使用
<body>
我是s3
{% include "s2.html" %}
{% macro func_mac(tp,na) %}
<input type="{{ tp }}" name="{{ na }}">
{% endmacro %}
{{ func_mac('text','username') }}
{{ func_mac('password','pwd') }}
{% macro my_func(my_type,my_name) %}
<input type="{{ my_type }}" name="{{ my_name }}">
{% endmacro %}
{{ my_func('file','sendfile') }}
</body>
s2页面
s3页面
Flask Session
form flask import session
app.secret_key = "!@#$%^@#$%^&*("
#设置用户的session
session["user"] = "value"
if session.get("user"):
return "200OK"
模拟登录设置seesion
from flask import Flask, request, render_template, redirect, session
app = Flask(__name__)
#秘钥必须要有
app.secret_key = "!@#$%^%^&*()_)(*&^%$@#$%^&*("
def to_login(func):
def inner(*args, **kwargs):
if session.get("user"):
ret = func(*args, **kwargs)
return ret
else:
return redirect("login")
return inner
@app.route("/index", methods=["GET", "POST"])
@to_login
def index():
if request.method == "GET":
return render_template("index.html")
else:
session["user"] = request.form.get("username")
return redirect("/detail")
@app.route('/detail')
def detail():
return render_template("detail.html")
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "GET":
return render_template('login.html')
else:
username = request.form.get("username")
password = request.form.get("password")
print(request.values)
print("value")
print(username, password)
session["user"] = username
return redirect("/index")
app.run(debug=True)