python之初识Flask

一、初识Flask

Python三大主流Web框架对比

1、三大框架的特点

  • Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架
  • Tornado 主要特点是原生异步非阻塞,在IO密集型应用和多任务处理上占据绝对性的优势,属于专注型框架
  • Flask 主要特点小而轻,原生组件几乎为0, 三方提供的组件请参考Django 非常全面,属于短小精悍型框架

2、三大框架的优缺点 

  • Django 通常用于大型Web应用由于内置组件足够强大所以使用Django开发可以一气呵成
  • Tornado 通常用于API后端应用,游戏服务后台,其内部实现的异步非阻塞真是稳得一批
  • Flask 通常应用于小型应用和快速构建应用,其强大的三方库,足以支撑一个大型的Web应用
  • Django 优点是大而全,缺点也就暴露出来了,这么多的资源一次性全部加载,肯定会造成一部分的资源浪费
  • Tornado 优点是异步,缺点是干净,连个Session都不支持
  • Flask 优点是精悍简单,缺点是组件大都来自第三方等

关于上面的总结

Django:

  优点:

    大而全,admin,models,Form,中间件,session

    一个框架解决所有问题

  缺点:

    一旦启动,所有资源全部加载,用不到的,浪费了

    太大了,结构复杂

    所有的组件,全部由Django自身控制

Flask:

  优点:

    轻、短小精悍

    快、最短三行代码就能开启服务

  缺点:

    组件大部分都来自第三方,如flask-admin, flask-session

    flask大版本更新,组件更新速度慢

Tornado:

  优点:

    原生的websocket

    异步io

    非阻塞

  缺点:

    三方和原组件几乎为零

Flask的准备工作

首先我们要安装Flask,具体操作如下:

  pip install Flask   

也可以通过pycharm在里面直接搜索Flask点击安装就好。还有其他的一些安装在这里就不在说了

三行代码启动Flask

from flask import Flask
app = Flask(__name__)
app.run()

  执行上面的代码我么在控制台可以看到一下一行代码

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

从上面可以看出默认访问的端口是5000,

我们访问该页面

上面给我的提示是没有相应的路由,因为我们根本没有配置,不过这个时候服务已经起来了

这个就是三行代码启动Flask服务

我们来写一个真正的第一个flask程序

from flask import Flask  # 导入Flask类

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


# url与视图映射
@app.route('/')  # app中的route装饰器
def hello_world():  # 视图函数
    return 'Hello World!'  # 返回的响应体


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

 启动上面代码并访问相应的页面我们在页面上就会看到'Hello World'的字样

路由系统

url传参的方式

普通的传参

@app.route('/user/<id>/')  # app中的route装饰器
def hello_world(id):  # 视图函数
    return '你是第{}个用户'.format(id)  # 返回的响应体

指定参数类型

有以下几种参数类型:

  • string:默认的数据类型
  • int:接收整型
  • float:浮点型
  • path:和string类似,这里可以接收斜杠
  • any:可以指定多个路径
  • uuid:只接受uuid字符串

(1) any

@app.route('/<any(blog,user):url_path>/<id>/')
def detail(url_path,id):
    if url_path == 'blog':
        return '博客详情{}'.format(id)
    else:
        return '用户详情{}'.format(id)

 

注意:上面的路由 '/<any(blog,user):url_path>/<id>/'写的时候一定要加上'/'反斜杠,要不会出错

 (2)path

@app.route('/article/<path:test>/')
def test_article(test):
    return 'test_article:{}'.format(test)

 有上面的图片可以看出来只要是前面匹配成功了,后面所有的包含'/'都会当做path。

endpoint

endpoint:反向生成url

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import url_for

app = Flask(__name__)


# 这里的endpoint我们可以不写,不写就默认为index和函数名一样
@app.route('/index/', endpoint='first')
def index():
    print(url_for('first'))  # 如果上面没有穿endpoint得话就写'index'
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

访问:http://127.0.0.1:5000/index/

pycharm控制台得到

/index/

这个不算是完整的url要想得到完整的url我们修改后为

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import url_for

app = Flask(__name__)


# 这里的endpoint我们可以不写,不写就默认为index和函数名一样
@app.route('/index/', endpoint='first')
def index():
    print(url_for('first',_external=True))  # 如果上面没有穿endpoint得话就写'index'
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

pycharm控制台输出为:

http://127.0.0.1:5000/index/

这样还是不够当我们后面有参数的时候怎么办

使用下面的方式:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import url_for,request

app = Flask(__name__)


# 这里的endpoint我们可以不写,不写就默认为index和函数名一样
@app.route('/index/', endpoint='first')
def index():
    stu_id = int(request.args['id'])
    print(url_for('first', _external=True, id=stu_id))  # 如果上面没有穿endpoint得话就写'index'
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

访问:http://127.0.0.1:5000/index/?id=1

pycharm控制台得到的输出为:

http://127.0.0.1:5000/index/?id=1

defaults

defaults : 视图函数的参数默认值{"nid":100}

注意:视图函数必须要设置形参nid,否则报错!

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import url_for,request

app = Flask(__name__)


# 这里的endpoint我们可以不写,不写就默认为index和函数名一样
@app.route('/index/', endpoint='first', defaults={'nid':100})
def index(nid):
    stu_id = int(request.args['id'])
    print(url_for('first', _external=True, id=stu_id))  # 如果上面没有穿endpoint得话就写'index'
    print(nid)
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

访问:http://127.0.0.1:5000/index/?id=1

pycharm得到的结果为:

http://127.0.0.1:5000/index/?id=1
100

访问一个结尾不带斜线的url会被flask重定向到一个带斜线的规范url去,所以我们在写的时候还是要在路由后面加一个斜线

 响应

响应体 HttpResponse、Render、Redirect、jsonify

 HttpResponse

@app.route("/")  # app中的route装饰器
def index():  # 视图函数
    return "Hello World!"  # HttpResponse

在flask中的HttpResponse 其实就是直接返回字符串

 redirect

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import redirect

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


# url与视图映射
@app.route('/redi/')
def redi():
    return redirect('/')  # redirect跳转至"/"


@app.route('/')
def index():
    return 'Hello Word!'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

在上面我们启动后访问:  http://127.0.0.1:5000/redi/

会看到Hello World

render

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)

@app.route('/index/')
def index():
    return render_template('index.html')


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

在当前的py文件的同级目录下创建一个templates目录然后在该目录下创建一个index.html文件

index.html内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

 我们可以重启后访问后会出现一下结果

 

在上面我们写return render_template('index.html')

 会发现index.html这个飘黄我们可以在pycharm的右击templates -> Mark Directory as-->Template Folder

会跳出来一个选项选择yes就好,然后出来一个界面在右边有一个Tempalte language在后面我们选择Jinja2然后点击确定就好

 如果我们使用pycharm创建一个Flask项目就不会出现这个问题,但是现阶段建议自己手动操作,有利于更好的熟悉flask

jsonify

后端代码为

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import jsonify  # 导入flask中的jsonify

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


@app.route('/index/')
def index():
    return jsonify({'k1':'v1'})


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

访问http://127.0.0.1:5000/index/

得到下图:

定制响应头。

flask如何给自己定制一个响应头信息

后端代码为

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import make_response  # make_response专门是用来设置响应头的

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


@app.route('/index/')
def index():
    obj = make_response('qwer')
    obj.headers['aaaa'] = '123'
    obj.set_cookie('key', 'value')
    return obj


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

访问:http://127.0.0.1:5000/index/

我们可以看到浏览器中信息

页面为:

点击右键选择 检查(使用的是Google Chrome)

 可以看到我们在上面设置的请求头在这里能够看到

再看看我们的cookie

这个就是我们定制的响应头

request相关

每个框架中都有处理请求的机制(request),但是每个框架的处理方式和机制是不同的

为了了解Flask的request中都有什么东西,首先我们要写一个前后端的交互

基于HTML + Flask 写一段前后端的交互

先写一段儿HTML form表单中提交方式是post  action地址是 /test

login.html的代码为

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎登陆</h1>
<form action="/test/" method="post">
    <p>
        <input type="text" name="user" placeholder="请输入用户名">
    </p>
    <p>
        <input type="password" name="pwd" placeholder="请输入密码">
    </p>
    <input type="submit" value="提交">
</form>
</body>
</html>

我们写的flask的代码为

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


@app.route('/login/')
def index():
    return render_template('login.html')


@app.route('/test/')
def home():
    print(request)
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

我们访问http://127.0.0.1:5000/login/页面后随便输入用户名和密码或者直接提交就会出现下面的图示

这个提示是其请求的方式不被允许。

这个请求的方式不被允许是因为默认的路由只允许GET,我们提交的是POST所以这里不通过

request.methods

修改我们的flask代码

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


@app.route('/login/')
def index():
    return render_template('login.html')


@app.route('/test/', methods=['POST'])  # 表示只允许POST请求
def home():
    print(request)  # request对象
    print(request.method)
    print(request.form)
    print(request.form['user'])
    print(request.form.get('pwd'))
    print(request.form.keys())
    for i in request.form.keys():
        print(i)
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

重启后再次访问login然后输入用户名和密码都是admin,

控制台的输出为

<Request 'http://127.0.0.1:5000/test/' [POST]>
POST
ImmutableMultiDict([('user', 'admin'), ('pwd', 'admin')])
admin
admin
<dict_keyiterator object at 0x00000252AD6A0F48>
user
pwd

 上面的@app.route('/test/', methods=['POST'])

 后面的methods后面是列表,这个表示可以有多个值,所以我们想要允许什么的请求就在这里写上就好。

request.form

 上面我们Form表单提交的数据我们可以通过request.form拿到提交的数据。

print(request.form)  # ImmutableMultiDict([('user', 'xiao'), ('pwd', '123')])
# ImmutableMultiDict 它看起来像是的Dict 就用Dict的方法取值试一下吧
print(request.form["user"])  # admin
print(request.form.get("pwd"))  # admin
# 看来全部才对了, ImmutableMultiDict 似乎就是个字典,再来玩一玩它
print(list(request.form.keys()))  # ['user', 'pwd'] 看来是又才对了
#如果以上所有的方法你都觉得用的不爽的话
req_dict = dict(request.form)
print(req_dict)  # 如果你觉得用字典更爽的话,也可以转成字典操作(这里有坑)

request.args

request.args中保存的是url中传递的参数

修改后端的GET

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


@app.route('/login/')
def index():
    return render_template('login.html')


@app.route('/test/', methods=['POST', 'GET'])  # 表示只允许POST请求
def home():
    print(request.args)
    print(request.args['id'])
    print(request.args.get('age'))
    print(list(request.args.keys()))
    print(list(request.args.values()))
    req_dic = dict(request.args)
    print(req_dic)
    # print(request)  # request对象
    # print(request.method)
    # print(request.form)
    # print(request.form['user'])
    # print(request.form.get('pwd'))
    # print(request.form.keys())
    # for i in request.form.keys():
    #     print(i)
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

然后在url地址栏输入下面的url

http://127.0.0.1:5000/test/?id=13&age=28

得到如下页面

控制台我们得到的输出是

ImmutableMultiDict([('id', '13'), ('age', '28')])
13
28
['id', 'age']
['13', '28']
{'id': ['13'], 'age': ['28']}

 有上面的示列可以看出request.form和request.args的区别

request.form是获取form表单中的参数

request.args是获取url中参数的

request.values

前端代码改动部位为黄色

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎登陆</h1>
<form action="/test?id=18&age=20" method="post">
    <p>
        <input type="text" name="user" placeholder="请输入用户名">
    </p>
    <p>
        <input type="password" name="pwd" placeholder="请输入密码">
    </p>
    <input type="submit" value="提交">
</form>
</body>
</html>

后端代码为

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


@app.route('/login/')
def index():
    return render_template('login.html')


@app.route('/test', methods=['POST', 'GET'])  # 表示只允许POST和GET请求
def home():
    print(request.values)
    print(request.values.get('id'))
    print(request.values['user'])
    print(request.values.to_dict())
    # print(request.args)
    # print(request.args['id'])
    # print(request.args.get('age'))
    # print(list(request.args.keys()))
    # print(list(request.args.values()))
    # req_dic = dict(request.args)
    # print(req_dic)
    # print(request)  # request对象
    # print(request.method)
    # print(request.form)
    # print(request.form['user'])
    # print(request.form.get('pwd'))
    # print(request.form.keys())
    # for i in request.form.keys():
    #     print(i)
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

访问http://127.0.0.1:5000/login/输入用户名和密码分别为admin(这个用户名和密码随便输入)提交后在管理控制台的输出为

CombinedMultiDict([ImmutableMultiDict([('id', '18'), ('age', '20')]), ImmutableMultiDict([('user', 'admin'), ('pwd', 'admin')])])
18
admin
{'user': 'admin', 'pwd': 'admin', 'id': '18', 'age': '20'}

上面我们可以看到只要是一个参数我们都可以使用request.values来拿到

form表单的坑

如果我们url和form表单中的key重名的话,form中的同名的key中value会被url中的value覆盖

我们只要修改前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎登陆</h1>
<form action="/test?id=18&user=20" method="post">
    <p>
        <input type="text" name="user" placeholder="请输入用户名">
    </p>
    <p>
        <input type="password" name="pwd" placeholder="请输入密码">
    </p>
    <input type="submit" value="提交">
</form>
</body>
</html>

  我们还是访问登录页面输入用户名和密码都是admin看看控制台的输出

CombinedMultiDict([ImmutableMultiDict([('id', '18'), ('user', '20')]), ImmutableMultiDict([('user', 'admin'), ('pwd', 'admin')])])
18
20
{'user': '20', 'pwd': 'admin', 'id': '18'}

我们发现user变成了20,在这里我们输入的是admin

如果URL和form表单中的key重名的话,form表单的同名的key的value值会被URL中同名的key的value值覆盖。

request.cookies

request.cookies顾名思义就是读取cookies中的信息

注意:这个要想读取到cookies的信息就要开始浏览器的cookies

我们修改上面的代码中的home视图函数

@app.route('/test', methods=['POST', 'GET']) 
def home():
    print(request.cookies)
    return 'ok'

我们访问 http://127.0.0.1:5000/login/然后输入用户名和密码

在pycharm的控制台我们可以看到

{'csrftoken': 'b0km4BAdzLjbMtXzfGTjv6z4tyac0DMK6tznTZzBjzkGEWA05tLgNyO9gKE2oQFn', 'sessionid': 'nh9jpx3dtnztxbkykof4f8fltbi8q85n'}

request.headers 

根据表面的意思就是用来获取本次请求的请求头

修改代码中的home视图函数

@app.route('/test', methods=['POST', 'GET']) 
def home():
    print(request.headers)
    return 'ok'

我们在访问前面的http://127.0.0.1:5000/login/然后输入用户名和密码

在pycharm控制台得到的输出为

Host: 127.0.0.1:5000
Connection: keep-alive
Content-Length: 20
Cache-Control: max-age=0
Origin: http://127.0.0.1:5000
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 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: csrftoken=b0km4BAdzLjbMtXzfGTjv6z4tyac0DMK6tznTZzBjzkGEWA05tLgNyO9gKE2oQFn; sessionid=nh9jpx3dtnztxbkykof4f8fltbi8q85n

request.data

这个就是处理不了的就变成字符串存在request.data里面

request是基于mimetype进行处理的,这个如果不知道可以去百度一下。

关于mimetype的类型以及字符串可以看这个:http://www.w3school.com.cn/media/media_mimeref.asp

如果出现不属于杉树类型的描述,request就会将这些无法处理的参数转换为JSON数据存入data中

修改代码中home视图函数

@app.route('/test', methods=['POST', 'GET'])  
def home():
    print(request.data)
    return 'ok'

再重复上面的操作我们在pycharm的控制台上可以看到

b''

这里显示的是空,由上面的解释我们可以知道因为我们request能够处理,所以显示为空

request.files

如果遇到文件上传的话,request.files 里面存的是你上传的文件,但是 Flask 在这个文件的操作中加了一定的封装,让操作变得极为简单

前端的html代码为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h4>欢迎登陆</h4>
<form action="/test" method="post" enctype="multipart/form-data">
    <p>
        <input type="file" name="file">
    </p>
    <input type="submit" value="提交">
</form>
</body>
</html>

后端完整的代码为

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request

# 实例化一个Flask对象,传递__name__参数进去
app = Flask(__name__)


@app.route('/login/')
def login():
    return render_template('login.html')


@app.route('/test/', methods=['POST', 'GET'])  # 表示只允许POST和GET请求
def test():
    print(request.files)  # ImmutableMultiDict([('file', <FileStorage: 'test.txt' ('text/plain')>)])
    print(request.files["file"])  # <FileStorage: 'test.txt' ('text/plain')>
    my_file = request.files["file"]
    my_file.save("test3.txt")  # 保存文件,里面可以写完整路径+文件名
    return 'ok'


if __name__ == '__main__':
    # 这里面的端口我们是可以自己设置的,我这里就没有设置了还是默认的5000
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!默认是关闭的
    app.run(debug=True)  # 启动Flask服务

访问http://127.0.0.1:5000/login/

选择一个文件上传

点击提交后

再看看我们pycharm的控制台的输出

ImmutableMultiDict([('file', <FileStorage: 'test.txt' ('text/plain')>)])
<FileStorage: 'test.txt' ('text/plain')>

request.获取各种路径

关于下面的这些路径我们知道有这个就好

# 获取当前的url路径
print(request.path)  
# 当前url路径的上一级路径
print(request.script_root)  
# 当前url的全部路径
print(request.url)  
# 当前url的路径的上一级全部路径
print(request.url_root)  

 request.json

如果在请求中我们写入"application/json" ,在使用request.json则返回json解析数据,否则返回None

 模板语言Jinja2

Jinja2

Flask中默认的模板语言就是Jinja2

我们在后端定义几个数据,用于传递到前端使用。

STUDENT = {'name': '温碧霞', 'age': 18, 'gender': ''}

STUDENT_LIST = [
    {'name': '温碧霞', 'age': 18, 'gender': ''},
    {'name': '胡歌', 'age': 22, 'gender': ''},
    {'name': '杨幂', 'age': 26, 'gender': ''}
]

STUDENT_DICT = {
    1: {'name': '温碧霞', 'age': 18, 'gender': ''},
    2: {'name': '胡歌', 'age': 22, 'gender': ''},
    3: {'name': '杨幂', 'age': 26, 'gender': ''},
}

 下面来学习一下关于Jinja2模板中的一些流程控制:

for

{% for foo in val %}
{{ foo }}
{% endfor %}

if

{% if val0 %}

{% elif val %}
    
{% else %}
    
{% endif %}

下面我们对上面的几种数据分别进行传递,并在前端显示成表格。

 字典

1、使用STUDENT字典传递至前端

目录结构:

后端代码

from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request  # 导入flask中的request

app = Flask(__name__)

STUDENT = {'name': '温碧霞', 'age': 18, 'gender': ''}

STUDENT_LIST = [
    {'name': '温碧霞', 'age': 18, 'gender': ''},
    {'name': '胡歌', 'age': 22, 'gender': ''},
    {'name': '杨幂', 'age': 26, 'gender': ''}
]

STUDENT_DICT = {
    1: {'name': '温碧霞', 'age': 18, 'gender': ''},
    2: {'name': '胡歌', 'age': 22, 'gender': ''},
    3: {'name': '杨幂', 'age': 26, 'gender': ''},
}


@app.route("/student")
def student():
    return render_template("student.html", student=STUDENT)


if __name__ == '__main__':
    app.run(debug=True)

前端student.html代码(这个tudent.html在后端代码统计目录下的templates下)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>学生列表</h3>
<div>{{ student }}</div>
<table border="1px">
    <tr>
        <td>{{ student.name }}</td>
        <td>{{ student["age"] }}</td>
        <td>{{ student.get("gender") }}</td>
    </tr>
</table>
</body>
</html>

访问http://127.0.0.1:5000/student可以得到

从这个例子中,可以看出来,字典传入前端Jinja2 模板语言中的取值操作, 与Python中的Dict操作极为相似,并且多了一个student.name的对象操作

列表

目录结构:

2. STUDENT_LIST 列表传入前端Jinja2 模板的操作:

后端:

from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request  # 导入flask中的request

app = Flask(__name__)

STUDENT = {'name': '温碧霞', 'age': 18, 'gender': ''}

STUDENT_LIST = [
    {'name': '温碧霞', 'age': 18, 'gender': ''},
    {'name': '胡歌', 'age': 22, 'gender': ''},
    {'name': '杨幂', 'age': 26, 'gender': ''}
]

STUDENT_DICT = {
    1: {'name': '温碧霞', 'age': 18, 'gender': ''},
    2: {'name': '胡歌', 'age': 22, 'gender': ''},
    3: {'name': '杨幂', 'age': 26, 'gender': ''},
}


@app.route("/student_list")
def student_list():
    return render_template("student.html", student=STUDENT_LIST)


if __name__ == '__main__':
    app.run(debug=True)

后端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>学生列表</h3>
<div>{{ student }}</div>
<table border="1px">
    {% for foo in student %}
    <tr>
        <td>{{ foo }}</td>
        <td>{{ foo.name }}</td>
        <td>{{ foo.get('age') }}</td>
        <td>{{ foo['gender'] }}</td>
    </tr>
    {% endfor %}
</table>
</body>
</html>

 访问  http://127.0.0.1:5000/student_list

从上面我们可以看出,如果需要循环遍历的话Jinja2给出的方案是

{% for foo in student %}
    <tr>
        <td>{{ foo }}</td>
    </tr>
{% endfor %}

 前端修改后:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>学生列表</h3>
<div>{{ student }}</div>
<table border="1px">
    {% for foo in student %}
        <tr>
            <td>{{ foo }}</td>
        </tr>
    {% endfor %}
</table>
</body>
</html>

 还是访问刚刚那个网址:http://127.0.0.1:5000/student_list

大字典

目录结构和上面的一样

后端:

from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request  # 导入flask中的request

app = Flask(__name__)

STUDENT = {'name': '温碧霞', 'age': 18, 'gender': ''}

STUDENT_LIST = [
    {'name': '温碧霞', 'age': 18, 'gender': ''},
    {'name': '胡歌', 'age': 22, 'gender': ''},
    {'name': '杨幂', 'age': 26, 'gender': ''}
]

STUDENT_DICT = {
    1: {'name': '温碧霞', 'age': 18, 'gender': ''},
    2: {'name': '胡歌', 'age': 22, 'gender': ''},
    3: {'name': '杨幂', 'age': 26, 'gender': ''},
}


@app.route("/student_dict")
def student_dict():
    return render_template("student.html", student=STUDENT_DICT)


if __name__ == '__main__':
    app.run(debug=True)

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>学生列表</h3>
<div>{{ student }}</div>
<table border="1px">
    {% for foo in student %}
        <tr>
            <td>{{ foo }}</td>
            <td>{{ student.get(foo).name }}</td>
            <td>{{ student[foo].get("age") }}</td>
            <td>{{ student[foo]["gender"] }}</td>
        </tr>
    {% endfor %}
</table>
</body>
</html>

访问:http://127.0.0.1:5000/student_dict

得到以下

由上面可以知道在遍历字典的时候,foo其实就是字典的key值

数据集合

把所有的数据类型传递到前端

目录结构还是上面的一样。

后端:

from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request  # 导入flask中的request

app = Flask(__name__)

STUDENT = {'name': '温碧霞', 'age': 18, 'gender': ''}

STUDENT_LIST = [
    {'name': '温碧霞', 'age': 18, 'gender': ''},
    {'name': '胡歌', 'age': 22, 'gender': ''},
    {'name': '杨幂', 'age': 26, 'gender': ''}
]

STUDENT_DICT = {
    1: {'name': '温碧霞', 'age': 18, 'gender': ''},
    2: {'name': '胡歌', 'age': 22, 'gender': ''},
    3: {'name': '杨幂', 'age': 26, 'gender': ''},
}


@app.route("/allstudent")
def all_student():
    return render_template("student.html", student=STUDENT,
                           student_list=STUDENT_LIST,
                           student_dict=STUDENT_DICT)


if __name__ == '__main__':
    app.run(debug=True)

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>学生列表</h3>
<div> _____________________________________</div>
Welcome to : student
<div>{{ student }}</div>
<table border="1px">
    <tr>
        <td>{{ student.name }}</td>
        <td>{{ student["age"] }}</td>
        <td>{{ student.get("gender") }}</td>
    </tr>
</table>
<div> _____________________________________</div>
Welcome to : student_list
<div>{{ student_list }}</div>
<table border="1xp">
    {% for foo in student_list %}
        <tr>
            <td>{{ foo }}</td>
            <td>{{ foo.name }}</td>
            <td>{{ foo.get("age") }}</td>
            <td>{{ foo["gender"] }}</td>
        </tr>
    {% endfor %}
</table>
<div> _____________________________________</div>
Welcome to : student_dict
<div>{{ student_dict }}</div>
<table border="1xp">
    {% for foo in student_dict %}
        <tr>
            <td>{{ foo }}</td>
            <td>{{ student_dict.get(foo).name }}</td>
            <td>{{ student_dict[foo].get("age") }}</td>
            <td>{{ student_dict[foo]["gender"] }}</td>
        </tr>
    {% endfor %}
</table>
</body>
</html>

 访问网页:http://127.0.0.1:5000/allstudent

从中我们可以看到,这个和Django一样可也以传递多个关键字

 **{}字典

利用**{}字典的方式传递参数

目录结构不变

前端代码和上一个一样

后端代码

from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template
from flask import request  # 导入flask中的request

app = Flask(__name__)

STUDENT = {'name': '温碧霞', 'age': 18, 'gender': '女'}

STUDENT_LIST = [
    {'name': '温碧霞', 'age': 18, 'gender': '女'},
    {'name': '胡歌', 'age': 22, 'gender': '男'},
    {'name': '杨幂', 'age': 26, 'gender': '女'}
]

STUDENT_DICT = {
    1: {'name': '温碧霞', 'age': 18, 'gender': '女'},
    2: {'name': '胡歌', 'age': 22, 'gender': '男'},
    3: {'name': '杨幂', 'age': 26, 'gender': '女'},
}


@app.route("/allstudent")
def all_student():
    return render_template("student.html", **{"student": STUDENT,
                                              "student_list": STUDENT_LIST,
                                              "student_dict": STUDENT_DICT})


if __name__ == '__main__':
    app.run(debug=True)

 同样访问http://127.0.0.1:5000/allstudent

得到的界面和上一个是一样的

 Jinja2的高阶用法之模板渲染

Jinja2 模板语言为我们提供了很多功能,下面介绍有关的功能及用法

安全相关的safe和MarkUp

没错这个和Django从后端传递html到前端,flask的safe和MarkUp和Django的safe和mark_safe对应

safe

后端代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, session, redirect, request, url_for, render_template

app = Flask(__name__)


@app.route('/index/')
def index():
    txt = "<input type='text' />"
    return render_template('index.html', txt=txt)


if __name__ == '__main__':
    app.run(debug=True)

前端代码:

<!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>
{{ txt| safe }}
</body>
</html>

访问:http://127.0.0.1:5000/index/

可以看到页面为:

这样我们可以知道通过前端使用{{ txt|safe }}标记为后端的传过来的为安全的。

MarkUp

MarkUp和safe相反的写在后端的处理方式

后端代码为:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, session, redirect, request, url_for, render_template, Markup

app = Flask(__name__)


@app.route('/index/')
def index():
    txt = Markup("<input type='text' />")
    return render_template('index.html', txt=txt)


if __name__ == '__main__':
    app.run(debug=True)

后端的代码为:

<!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>
{{ txt }}
</body>
</html>

  上面的代码结构index.html都是在后端代码同级目录下的templates目录下的index.html

执行函数

Flask对于传入的函数是不自动执行的,而Django是自动执行的

后端代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, session, redirect, request, url_for, render_template, Markup

app = Flask(__name__)


def ab_sum(a, b):
    return a + b


@app.route('/index/')
def index():
    return render_template('index.html', func=ab_sum)


if __name__ == '__main__':
    app.run(debug=True)

前端代码

<!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>
{{ func }}
<br/>
{#后端的函数需要传如2个参数#}
{{ func(1,9) }}
</body>
</html>

  

网址访问:http://127.0.0.1:5000/index/

会出现的结果为10。这里我们可以看到我们的Flask的在传参方面很接近python。所以当我们直接写函数名的时候就会出现一个

 上面使我们定义函数后把函数传到后端,在这里我们可以定义全局函数,不需要传参的就可以使用

后端代码为:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, session, redirect, request, url_for, render_template, Markup

app = Flask(__name__)


@app.template_global('ab')  # 定义全局模板函数(这个'ab'表示的全局模板定义的函数名如果不写就是用我们下面自己定义的函数名为ab_sum)
def ab_sum(a, b):  # 这里可以传递多个参数前端使用和python使用一样
    return a + b


@app.template_filter('abc')  # 定义全局模板函数(如果不写就是abc_sum)
def abc_sum(a, b, c):  # 前端使用该函数的格式为{{ 3|abc(6,9) }}第一个参数是在首位为3
    return a + b + c


# 上面的'abc'表示在全局取名为abc,调用的时候是{{ 3|abc(6,9) }},如果只传一个参数的时候我们在后端可以不用{{ 3|abc() }}或{{ 3|abc }}

@app.route('/index/')
def index():
    return render_template('index.html')


if __name__ == '__main__':
    app.run(debug=True)

前端代码:

<!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>
{#函数#} {{ ab(1,9) }} <br/>
 {#过滤器#}
{{ 3|abc(6,9) }} 
</body>
</html>

  

两个函数的调用方式不太一样

尤其是@app.template_filter() 它的调用方式比较特别,这是两个Flask中的特殊装饰器

 刷新页面为:

模板复用block

前端代码:

layout.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>
    <h1>模板</h1>
    {% block content %}{% endblock %}
</body>
</html>

login.html

{% extends "layout.html" %}
{% block content %}
    <h4>欢迎登陆</h4>
    <form>
        用户名:<input type="text" name="user">
        密码:<input type="text" name="pwd">
        <input type="submit" value="提交">
    </form>
{% endblock %}

index.html

{% extends "layou.html" %}
{% block content %}
    <h1>欢迎来到py3study.com</h1>
{% endblock %}

后端代码:

from flask import Flask  # 导入Flask类
from flask import render_template  # 导入flask中的render_template

app = Flask(__name__)

@app.route("/login")
def login():
    return render_template("login.html")


@app.route("/home")
def home():
    return render_template("home.html")

if __name__ == '__main__':
    app.run("0.0.0.0", 5000, debug=True)

 访问:http://127.0.0.1:5000/login/

访问:http://127.0.0.1:5000/home/

引用include

Jinja2模板语言的模块引用 include

login.html的文件内容

<h4>欢迎登陆</h4>
<form>
    用户名:<input type="text" name="user">
    密码:<input type="text" name="pwd">
    <input type="submit" value="提交">
</form>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>欢迎登录</h1>
    {% include "login.html" %}

</body>
</html>

后端代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, session, redirect, request, url_for, render_template, Markup

app = Flask(__name__)


@app.route("/index/")
def index():
    return render_template("index.html")


if __name__ == '__main__':
    app.run(debug=True)

访问:http://127.0.0.1:5000/index/

宏定义

前端

index.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h1>Welcome to My</h1>
    {#type_text接收2个参数name,type#}
    {% macro type_text(name,type) %}
    {#渲染2个参数#}
    <input type="{{ type }}" name="{{ name }}" value="{{ name }}">
    {% endmacro %}

    <h2>在下方是使用宏来生成input标签</h2>
    {#执行宏定义#}
    {{ type_text("one","text") }}
    {{ type_text("two","text") }}

</body>
</html>

  后端代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, session, redirect, request, url_for, render_template, Markup

app = Flask(__name__)


@app.route("/index/")
def index():
    return render_template("index.html")


if __name__ == '__main__':
    app.run(debug=True)

 访问:http://127.0.0.1:5000/index/

宏定义一般情况下很少应用到,但是要知道有这么个概念

配置文件

flask是一个非常灵活且短小精悍的web框架。

flask有一个叫做配置的东西,先展示一下这个东东。

代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, session, redirect, request, url_for, render_template, Markup

app = Flask(__name__)


@app.route("/login/")
def login():
    return render_template("login.html")


@app.route("/home/")
def home():
    return render_template("home.html")


if __name__ == '__main__':
    app.run(debug=True)

上面的代码表示当我们的代码发生变化后会自动重启Flask程序。

Flask的配置就是在 app.config 中添加一个键值对,但是你存进去的键必须是config中应该存在的,如果不再存在的话,它会默认无用,就这么放着

config中有多少有用的key 呢?

{
    'DEBUG': False,  # 是否开启Debug模式
    'TESTING': False,  # 是否开启测试模式
    'PROPAGATE_EXCEPTIONS': None,  # 异常传播(是否在控制台打印LOG) 当Debug或者testing开启后,自动为True
    'PRESERVE_CONTEXT_ON_EXCEPTION': None,  # 一两句话说不清楚,一般不用它
    'SECRET_KEY': None,  # 之前遇到过,在启用Session的时候,一定要有它
    'PERMANENT_SESSION_LIFETIME': 31,  # days , Session的生命周期(天)默认31天
    'USE_X_SENDFILE': False,  # 是否弃用 x_sendfile
    'LOGGER_NAME': None,  # 日志记录器的名称
    'LOGGER_HANDLER_POLICY': 'always',
    'SERVER_NAME': None,  # 服务访问域名
    'APPLICATION_ROOT': None,  # 项目的完整路径
    'SESSION_COOKIE_NAME': 'session',  # 在cookies中存放session加密字符串的名字
    'SESSION_COOKIE_DOMAIN': None,  # 在哪个域名下会产生session记录在cookies中
    'SESSION_COOKIE_PATH': None,  # cookies的路径
    'SESSION_COOKIE_HTTPONLY': True,  # 控制 cookie 是否应被设置 httponly 的标志,
    'SESSION_COOKIE_SECURE': False,  # 控制 cookie 是否应被设置安全标志
    'SESSION_REFRESH_EACH_REQUEST': True,  # 这个标志控制永久会话如何刷新
    'MAX_CONTENT_LENGTH': None,  # 如果设置为字节数, Flask 会拒绝内容长度大于此值的请求进入,并返回一个 413 状态码
    'SEND_FILE_MAX_AGE_DEFAULT': 12,  # hours 默认缓存控制的最大期限
    'TRAP_BAD_REQUEST_ERRORS': False,
    # 如果这个值被设置为 True ,Flask不会执行 HTTP 异常的错误处理,而是像对待其它异常一样,
    # 通过异常栈让它冒泡地抛出。这对于需要找出 HTTP 异常源头的可怕调试情形是有用的。
    'TRAP_HTTP_EXCEPTIONS': False,
    # Werkzeug 处理请求中的特定数据的内部数据结构会抛出同样也是“错误的请求”异常的特殊的 key errors 。
    # 同样地,为了保持一致,许多操作可以显式地抛出 BadRequest 异常。
    # 因为在调试中,你希望准确地找出异常的原因,这个设置用于在这些情形下调试。
    # 如果这个值被设置为 True ,你只会得到常规的回溯。
    'EXPLAIN_TEMPLATE_LOADING': False,
    'PREFERRED_URL_SCHEME': 'http',  # 生成URL的时候如果没有可用的 URL 模式话将使用这个值
    'JSON_AS_ASCII': True,
    # 默认情况下 Flask 使用 ascii 编码来序列化对象。如果这个值被设置为 False ,
    # Flask不会将其编码为 ASCII,并且按原样输出,返回它的 unicode 字符串。
    # 比如 jsonfiy 会自动地采用 utf-8 来编码它然后才进行传输。
    'JSON_SORT_KEYS': True,
    #默认情况下 Flask 按照 JSON 对象的键的顺序来序来序列化它。
    # 这样做是为了确保键的顺序不会受到字典的哈希种子的影响,从而返回的值每次都是一致的,不会造成无用的额外 HTTP 缓存。
    # 你可以通过修改这个配置的值来覆盖默认的操作。但这是不被推荐的做法因为这个默认的行为可能会给你在性能的代价上带来改善。
    'JSONIFY_PRETTYPRINT_REGULAR': True,
    'JSONIFY_MIMETYPE': 'application/json',
    'TEMPLATES_AUTO_RELOAD': None,
}

以上这些Key,都可以被改写,当然他们也都是有默认值存在的,如果没有特殊情况,不要改写它的默认值。

修改配置的方式

方式一:

向上面那样直接修改

app.config["DEBUG"] = True

方式二:

类的导入

首先要创建一个setting.py的文件。

from datetime import timedelta


class Config(object):
    DEBUG = False
    TESTING = False
    SECRET_KEY = "asdfasdfas23"
    DATABASE_URI = 'sqlite://:memory:'

    SESSION_COOKIE_NAME = 'session'
    SESSION_COOKIE_DOMAIN = None
    SESSION_COOKIE_PATH = None
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = False
    SESSION_REFRESH_EACH_REQUEST = True
    PERMANENT_SESSION_LIFETIME = timedelta(hours=1)


class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'


class DevelopmentConfig(Config):
    DEBUG = True


class TestingConfig(Config):
    TESTING = True

上面写了多个就是为了我们在实际中切换环境配合不同的环境

在flask程序中

from flask import Flask
app = Flask(__name__) # 应用配置类 

app.config.from_object("settings.DevelopmentConfig")

if __name__ == '__main__':
  app.run()

或者:

from flask import Flask
# 导入自定义配置文件的配置类
import setting
app = Flask(__name__) # 应用配置类 

app.config.from_object(settings.DevelopmentConfig) 

if __name__ == '__main__': 
  app.run()

关于如何给一个 路由加上一个登录认证

方式一:

后端代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, render_template, request, session, redirect

app = Flask(__name__)
# app.config['SESSION_COOKIE_NAME'] = 'session'
app.config['SECRET_KEY'] = 'lkjhgffddda'  # 使用seesion这个一定要设置,上面关于参数也写了。


@app.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'qwe' and pwd == 'qwe':
        session['user'] = user
        return redirect('/index/')
    return render_template('login.html', error='用户名或密码错误')


@app.route('/index/')
def index():
    user = session.get('user')
    if not user:
        return redirect('/login/')
    return 'ok'


if __name__ == '__main__':
    app.run()

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>
    <h1>用户登录</h1>
    <form method="post">
        <input type="text" name="user">
        <input type="password" name="pwd">
        <input type="submit" value="提交">{{error}}
    </form>
</body>
</html>

方式二:

后端代码

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, render_template, request, session, redirect, url_for

app = Flask(__name__)
# app.config['SESSION_COOKIE_NAME'] = 'session'
app.config['SECRET_KEY'] = 'lkjhgffddda'

import functools


def auth(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        if not session.get('user'):
            return redirect(url_for('login'))
        ret = func(*args, **kwargs)
        return ret

    return inner


@app.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    user = request.form.get('user')
    pwd = request.form.get('pwd')
    if user == 'qwe' and pwd == 'qwe':
        session['user'] = user
        return redirect('/index/')
    return render_template('login.html', error='用户名或密码错误')


@app.route('/index/')
@auth
def index():
    return 'ok'


if __name__ == '__main__':
    app.run(debug=True)

应用场景:比较少的函数中需要额外添加功能。

前端代码不变

方式三:

后端代码:

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask, render_template, request, session, redirect, url_for

app = Flask(__name__)
# app.config['SESSION_COOKIE_NAME'] = 'session'
app.config['SECRET_KEY'] = 'lkjhgffddda'

# 这个就没每当请求近来后第一个走的就是这个函数。类似于Django的中间件
@app.before_request def xxxxxx(): if request.path == '/login/': return None if session.get('user'): return None return redirect('/login/') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'qwe' and pwd == 'qwe': session['user'] = user return redirect('/index/') return render_template('login.html', error='用户名或密码错误') @app.route('/index/') def index(): return 'ok' if __name__ == '__main__': app.run(debug=True)

前端代码不变。上面的login.html都在后端代码同级目录下的templates目录下面创建的。

 下面来说一说session

当请求刚到来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,将该值解密并反序列化成字典,放入内存以便视图函数使用。

当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。

闪现

在session中存储一个数据,读取时通过pop将数据移除。
from flask import Flask,flash,get_flashed_messages

后端代码

#!/usr/bin/env python
# -*-coding:utf-8-*-
from flask import Flask,flash,get_flashed_messages
app = Flask(__name__)


@app.route('/page1/')
def page1():
    # session['uuuuu'] = 123
    flash('临时数据存储', 'error')
    flash('sdfsdf234234', 'error')
    flash('adasdfasdf', 'info')

    return "Session"


@app.route('/page2/')
def page2():
    # print(session['uuuuu'])
    # del session['uuuuu']
    # session.pop('uuuuu')
    print(get_flashed_messages(category_filter=['error']))
    return "Session"


if __name__ == '__main__':
    app.run(debug=True)

我们先访问:http://127.0.0.1:5000/page1/相当于把数据放到进去

在访问http://127.0.0.1:5000/page2/相当于取数据,

我们在pycharm控制台看到

['临时数据存储','sdfsdf234234']

上面取数据的的时候,只取error的数据所以看到上面的结果。

猜你喜欢

转载自www.cnblogs.com/yang-China/p/10032680.html