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’)])

python flask 返回 文件 flask return_html

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” 的文件了,操作还是很简单的

  1. 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/
  1. 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文件。

  1. 默认模板路径:项目根目录下的templates文件夹。
  2. 自定义模板路径:如果不想使用默认的模板路径,即项目根目录的templates文件夹,可以在实例化flask时指定参数template_folder的值,以指定默认模板的路径。
  3. 模板传参:如果需要给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>

结果

python flask 返回 文件 flask return_html_02

markupsaf后端控制生成标签代码

@app.route("/test")
def test():
    mylable=' <input type="file" name="file">'
    return render_template('test.html',mylable=mylable)
app.run(debug=True)

python flask 返回 文件 flask return_html_03

方法一:前端加|safe即可

<body>
{{ mylable |safe }}
</body>

python flask 返回 文件 flask return_flask_04

或者后端使用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)

python flask 返回 文件 flask return_flask_05


前端

{{ 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}}

python flask 返回 文件 flask return_html_06

替换之后的结果

{{ txt|my_cut }}

python flask 返回 文件 flask return_flask_07

模板的继承

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页面

python flask 返回 文件 flask return_html_08

s3页面

python flask 返回 文件 flask return_python flask 返回 文件_09

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)