zoukankan      html  css  js  c++  java
  • Flask&&人工智能AI --1

    Flask初识,Response三剑客,jsonify以及send_file、Request,模板语言 Jinja2,用户登录例子,内置Sessio

    一、Flask初识

    首先,要看你学没学过Django 如果学过Django 的同学,请从头看到尾,如果没有学过Django的同学,并且不想学习Django的同学,轻饶过第一部分

    三大主流Web框架对比

    1、Django:

      优点:大而全,集成了很多组件,Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架;django通常用于大型Web引用,由于内置组件足够强大,所以使用Django开发可以一气呵成

      缺点:这么多资源一次性加载会造成一部分资源浪费

    2、Flask:

      优点: 小而轻,原生组件几乎为0,三方提供的组建请参开Django非常全面,属于短小精悍型框架;通常应用于小型应用和快速构建应用,其强大的三方库,足以支撑一个大型的Web应用

      缺点:稳定性相对较差

    3、Tornado

      优点:原生异步非阻塞,在IO密集型应用型和多任务处理上占据绝对性的优势,属于专注型框架;通常用于API后端应用,游戏服务后台,其内部四线的异步非阻塞老稳了。

      缺点:干净,三方及原生组件几乎为0,连个session都不支持 

    Flask 的安装与HelloWorld

    Flask的安装特别难,但是鄙人很懒,肯定会找出一个最简单的方法教你们,具体操作如下:

    pip install Flask

    别问我还有没有复杂的方法,没有!

    Flask安装完成了,下面使用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,访问页面:

    因为没有定义路由,所以报404。但是服务是起来了!

    六行Flask

    from flask import Flask
    app = Flask(__name__)
    @app.route("/")
    def index():
        return "HelloWord!"
    app.run()

    重启程序,刷新页面

     实现了Flask的第一个HelloWord程序

    解读一下代码:

    from flask import Flask    #导入flask类
    app = Flask(__name__)  #实例化Flask对象app
    @app.route("/")    #app中的route装饰器
    def index():    #视图函数
        return "HelloWord!"   #返回响应体
    
    # 监听地址为0.0.0.0,表示服务器的所有网卡
    # 5000是监听端口
    # debug=True表示启动debug模式。当代码有改动时,Flask会自动加载,无序重启!
    app.run("0.0.0.0",5000,debug=True)  # 启动Flask服务

    注意:!!!  默认的debug模式是关闭的。如有代码改动,需要重启flask才能生效!但是开启的debug模式,代码一定有改动,会立刻加载,无需重启!!!

    还有一点,app = Flask(__name__)  这里面的__name__  表示 标识模块的名字的一个系统变量还可以是app=Flask(”dsds“),这样运行也没有问题。那么为什么要用__name__呢?后面学习到蓝图会用到!

    启动了Flask,得到了返回值,打印在页面上

    本文参考:

    https://www.cnblogs.com/DragonFire/p/9254637.html

    二、Response三剑客 -- render、redirect、HttpResponse

    HttpResponse

    在Flask中的HttpResponse,其实就是返回字符串至客户端

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

    Redirect

    from flask import Flask  # 导入Flask类
    from flask import redirect  # 导入flask中的redirect
    
    app = Flask(__name__)
    
    
    # app中的route装饰器,用来指定视图函数的URL地址
    @app.route("/redi")
    def redi():  # 视图函数
        return redirect("/")  # redirect跳转至"/"
    
    
    @app.route("/")
    def index():  # 视图函数
        return "hello"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)

    每当访问"/redi"这个地址的时候,视图函数redi会触发redirect("/") 跳转到url地址:  "/" 并会触发"/"对应的视图函数index()

    访问url:  http://127.0.0.1:5000/redi

    查看网页工具,查看网络。它经历了2次请求!

    render (render_template)

    编辑文件demo.py,代码如下

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    
    app = Flask(__name__)
    
    
    @app.route("/home")
    def home():  # 视图函数
        # 渲染html模板,返回html页面
        return render_template("home.html")
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)

    在当前py文件目录中创建templates,在此目录下创建文件home.hml

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

    重启flask,访问home页面,效果如下:

    目录结果如下:

    ./
    ├── demo.py
    └── templates
        └── home.html——

    HTML模板渲染是每个Web框架中都必须有的,至于render_template的具体用法,留个悬念,往后看

    注意: 如果要使用render_template返回渲染的模板,请在项目得主目录中加入一个目录remplates

    否则可能会有一个jinja2的异常

    遇到上述的问题,基本上就是你的template的路径问题

    为什么要一定要创建templates文件夹呢?叫abc,行不行呢?不行!

    看这一行代码

    app = Flask(__name__)

    使用Ctrl+鼠标左键,点击Falsk,查看源码

    def __init__(
        self,
        import_name,
        static_url_path=None,
        static_folder='static',
        static_host=None,
        host_matching=False,
        subdomain_matching=False,
        template_folder='templates',
        instance_path=None,
        instance_relative_config=False,
        root_path=None
    ):
    View Code

    看到template_folder变量没有?文件必须叫这个名字~

    指定templates路径

    注意:我的flask程序,是直接用新建py文件写的。所以这一行代码,会飘黄

    return render_template("home.html")

    怎么解决呢?很简单!执行目录就好了

    右键templates文件夹-->Mark Directory as-->Template Folder

    选择yes

    选择Jinja2,Flask中默认的模板语言是Jinja2

    django的模板语言为django,其实django底层也是用Jinja2开发的。其他模板语言同理!

    后续会讲到flaks模板语法,你会发现,和django几乎是一样的!

    注意:如果直接使用Pycharm创建Flask项目,是不存在这个问题的!

    前期学习Flask,要先自己手动折腾,后期就可以用Pycharm创建了!

    本文参考链接:
    https://www.cnblogs.com/DragonFire/p/9255637.html

    三、Flask中小儿子 -- jsonify以及send_file

    四、Request

    from flask import request
    request.method  #请求方式
    request.form  #存放FromData中的数据to_dict序列化成字典
    request.args  #获取URL中的数据to_dict序列化字典
    request.url  #访问的完整路径
    request.path  #路由地址
    request.host  #主机地址
    request.values  #获取FormData  and  URL中的数据 ,不要用to_dict
    request.json  #如果提交时请求头中的Content-Type:accplication/json字典操作
    request.data  #如果提交时请求头中的Content-Type无法被识破,将请求体中的原始数据存放byte
    request.cookies  #获取Cookie中的数据
    request.headers  #获取请求头
    request。files #序列化文件存储save()

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

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

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

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

    在templates目录创建文件login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>login</title>
    </head>
    <body>
    <h1>欢迎登录</h1>
    <form action="/req" method="post" enctype="multipart/form-data">
        <p>
            <input type="text" name="username" placeholder="请输入用户名">
        </p>
        <p>
            <input type="text" name="password" placeholder="请输入用户密码">
        </p>
        <input type="submit" value="提交">
    </form>
    </body>
    </html>

    写好一个标准 form 表单,一点提交,搜就向后端提交一个POST请求过去了

    后端的接收方式就 666 了

    首先要从 flask 包中导入 request 模块 , 至于为什么要导入 request 呢? 这里不做解释,暂时你就知道 request 如果要用,需要导入

     

    demo.py

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request  # 导入flask中的request
    
    app = Flask(__name__)
    
    @app.route("/login")
    def login():
        return render_template("login.html")
    
    
    @app.route("/req")
    def home():  # 视图函数
        print(request)
        return "ok"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

     重启flask,访问登录页面

    提示之后,报错!提示请求方式不被允许!

    methods

     为什么呢?因为默认路由只允许GET访问。那么需要加一个参数methods,允许POST访问

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request  # 导入flask中的request
    
    app = Flask(__name__)
    
    @app.route("/login")
    def login():
        return render_template("login.html")
    
    
    @app.route("/req",methods=["POST"])  # 只允许POST
    def home():  # 视图函数
        print(request)  # request对象
        print(request.method)  # POST看来可以使用这种方式来验证请求方式
        # ImmutableMultiDict([('user', 'xiao'), ('pwd', '123')])
        print(request.form)
        # ImmutableMultiDict 它看起来像是Dict,使用字典方式取值
        print(request.form["user"])  # xiao
        print(request.form.get("pwd"))  # 123
        # 字典迭代器对象,keys表示获取所有值
        print(request.form.keys())
        # 既然是迭代器,就可以使用for循环了
        for i in request.form.keys():
            print(i)
    
        return "ok"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    重新提交一次,就可以了!

    查看Pycharm控制台输出:

    <Request 'http://127.0.0.1:5000/req' [POST]>
    POST
    ImmutableMultiDict([('user', 'xiao'), ('pwd', '123')])
    xiao
    <dict_keyiterator object at 0x0000027BF603FAE8>
    user
    pwd
    View Code

    解释一个 @app.route("/req",methods=["POST"]) :

    methods=["POST"]  代表这个url地址只允许 POST 请求,是个列表也就是意味着可以允许多重请求方式,例如GET之类的

    request.method

    1.request.method 之 肯定知道前端用什么方式提交的

    Flask 的 request 中给我们提供了一个 method 属性里面保存的就是前端的请求的方式

    print(request.method) # POST 看来可以使用这种方式来验证请求方式

    request.form

    2.request.form 之 拿他来举例的话再好不过了

    Form表单中传递过来的值,使用request.form中拿到

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

    request.args

    3.request.args 之 你能看见的Url参数全在里面

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

    先把后端请求代码改动一下,允许POST和GET

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request  # 导入flask中的request
    
    app = Flask(__name__)
    
    @app.route("/login")
    def login():
        return render_template("login.html")
    
    
    @app.route("/req",methods=["POST","GET"])  # 只允许POST和GET
    def home():  # 视图函数
        print(request.args)  # ImmutableMultiDict([('id', '1'), ('age', '20')])
        print(request.args["id"])  # 1
        print(request.args.get("age"))  # 20
        print(list(request.args.keys()))  # ['id', 'age']
        print(list(request.args.values()))  # ['1', '20']
        req_dict = dict(request.args)  # {'id': ['1'], 'age': ['20']}
        print(req_dict)
    
        return "ok"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    然后使用URL地址直接传递参数

    http://127.0.0.1:5000/req?id=1&age=20

    然后会在控制台中看到,ImmutableMultiDict

    ImmutableMultiDict([('id', '1'), ('age', '20')])
    20
    ['id', 'age']
    ['1', '20']
    {'id': ['1'], 'age': ['20']}

    request.args 与 request.form 的区别就是:

    request.args 是获取url中的参数

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

    request.values

    4.request.values 之 只要是个参数我都要

    改动一下前端代码:

    <form action="/req?id=1&age=20" method="post">

    完整代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>欢迎登陆</h1>
    <form action="/req?id=1&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>
    View Code

    改动后端代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request  # 导入flask中的request
    
    app = Flask(__name__)
    
    @app.route("/login")
    def login():
        return render_template("login.html")
    
    
    @app.route("/req",methods=["POST","GET"])  # 只允许POST和GET
    def home():  # 视图函数
        print(
            request.values)  # CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('age', '20')]), ImmutableMultiDict([('user', 'xiao'), ('pwd', '123')])])
        print(request.values.get("id"))  # 1
        print(request.values["user"])  # Oldboy
        # 这回喜欢直接操作字典的小伙伴们有惊喜了! to_dict() 方法可以直接将我们的参数全部转为字典形式
        print(request.values.to_dict())  # {'user': 'xiao', 'pwd': '123', 'id': '1', 'age': '20'}
    
        return "ok"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    这是让我们在使用form表单提交的同时使用url参数提交

    访问登录页面,点击提交,查看Pycharm控制台输出:

    CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('age', '20')]), 
    ImmutableMultiDict([('user', 'xiao'), ('pwd', '123')])]) 1 xiao {'user': 'xiao', 'pwd': '123', 'id': '1',‘age':’20’}

    form表单的坑

    注意这里的坑来啦! 坑来啦!
    如果url和form中的Key重名的话,form中的同名的key中value会被url中的value覆盖
    http://127.0.0.1:5000/req?id=1&user=20

    修改login.html

    <form action="/req?id=1&user=20" method="post">

    完整代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>欢迎登陆</h1>
    <form action="/req?id=1&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>
    View Code

    重新访问登录页面,再次提交。

    查看Pycharm控制台输出:

    CombinedMultiDict([ImmutableMultiDict([('id', '1'), ('user', '20')]), ImmutableMultiDict([('user', 'xiao'), ('pwd', '123')])])
    1
    20
    {'user': '20', 'pwd': '123', 'id': '1'}
    View Code

    发现user变成了20 ,咦?我明明输入的是xiao啊

    如果url和form中的Key重名的话,form中的同名的key中value会被url中的value覆盖

    request.cookies

    5.request.cookies 之 存在浏览器端的字符串儿也会一起带过来

    前提是你要开启浏览器的 cookies

    request.cookies 是将cookies中信息读取出来

    修改demo.py中的home视图函数

    def home():  # 视图函数
        print(request.cookies)
        return "ok"

    重新登录一次,查看Pycharm控制台输出:

    {'Hm_lvt_080836300300be57b7f34f4b3e97d911': '1531653977', 'csrftoken': 'nO0pRJxevEVwRpCLzbEpNSAV4GdzO4aXJiE40AHopAkW0xkpzRE7p6gS2BngA4CA'}

    request.headers

    6.request.headers 之 请求头中的秘密

    用来获取本次请求的请求头

    修改demo.py中的home视图函数

    def home():  # 视图函数
        print(request.headers)
        return "ok"

    重新登录一次,查看Pycharm控制台输出:

    Host: 127.0.0.1:5000
    Connection: keep-alive
    Content-Length: 17
    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; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 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
    Cookie: Hm_lvt_080836300300be57b7f34f4b3e97d911=1531653977; csrftoken=nO0pRJxevEVwRpCLzbEpNSAV4GdzO4aXJiE40AHopAkW0xkpzRE7p6gS2BngA4CA
    View Code

    request.data

    7.request.data 之 如果处理不了的就变成字符串儿存在data里面

    你一定要知道 request 是基于 mimetype 进行处理的

    mimetype的类型 以及 字符串儿 : http://www.w3school.com.cn/media/media_mimeref.asp

    如果不属于上述类型的描述,request就会将无法处理的参数转为Json存入到 data 中

    其实我们可以将 request.data , json.loads 同样可以拿到里面的参数

    修改demo.py中的home视图函数

    def home():  # 视图函数
        print(request.data)
        return "ok"

    重新登录一次,查看Pycharm控制台输出:

    b''

    为什么是空的呢?注意:request处理不了的就变成字符串儿存在data里面!

    因为它能处理,所以才是空的!

    request.files

    8.request.files 之 给我一个文件我帮你保管

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

    首先改下前端代码:

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

    再改后端代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request  # 导入flask中的request
    
    app = Flask(__name__)
    
    @app.route("/login")
    def login():
        return render_template("login.html")
    
    
    @app.route("/req",methods=["POST","GET"])  # 只允许POST和GET
    def home():  # 视图函数
        print(request.files)  # ImmutableMultiDict([('file', <FileStorage: 'abc.txt' ('text/plain')>)])
        print(request.files["file"])  # <FileStorage: 'abc.txt' ('text/plain')>
        my_file = request.files["file"]
        my_file.save("123.txt")  # 保存文件,里面可以写完整路径+文件名
    
        return "ok"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    访问登录页面

    上传一个文件,比如是abc.txt

    点击提交,效果如下:

    查看Pycharm控制台输出:

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

    这样我们就成功的保存了一个名叫 "123.txt" 的文件了,操作还是很简单的。保存目录为当前py文件目录!

     注意:前端页面必须设置enctype="multipart/form-data",否则提交时,会报错

    request.获取各种路径 

    9. request.获取各种路径 之 这些方法没必要记,但是要知道它存在

    修改后端代码

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request  # 导入flask中的request
    
    app = Flask(__name__)
    
    @app.route("/login")
    def login():
        return render_template("login.html")
    
    
    @app.route("/req",methods=["POST","GET"])  # 只允许POST和GET
    def home():  # 视图函数
        # 获取当前的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/
    
        return "ok"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    直接访问页面

    查看Pycharm控制台输出:

    /req
    
    http://127.0.0.1:5000/req
    http://127.0.0.1:5000/

    request.json

    10. request.json 之 前提你得告诉是json

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

    修改后端代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request  # 导入flask中的request
    
    app = Flask(__name__)
    
    @app.route("/login")
    def login():
        return render_template("login.html")
    
    
    @app.route("/req",methods=["POST","GET"])  # 只允许POST和GET
    def home():  # 视图函数
        # 获取json数据
        print(request.json )
    
        return "ok"
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    使用postman发送一个json数据

    查看返回值

    查看Pycharm控制台输出:

    {'id': 1}

    本文参考链接:

    https://www.cnblogs.com/DragonFire/p/9259395.html

    四、模板语言 Jinja2

    Jinja2

    是时候开始写个前端了,Flask中默认的模板语言是Jinja2

    现在我们来一步一步的学习一下 Jinja2 捎带手把 render_template 中留下的疑问解决一下

    首先我们要在后端定义几个字符串,用于传递到前端

    STUDENT = {'name': '韩雪', 'age': 24, 'gender': ''}
    
    STUDENT_LIST = [
        {'name': '韩雪', 'age': 24, 'gender': ''},
        {'name': '舒畅', 'age': 23, 'gender': ''},
        {'name': '唐嫣', 'age': 25, 'gender': ''}
    ]
    
    STUDENT_DICT = {
        1: {'name': '韩雪', 'age': 24, 'gender': ''},
        2: {'name': '舒畅', 'age': 23, 'gender': ''},
        3: {'name': '唐嫣', 'age': 25, 'gender': ''},
    }

    但是前提我们要知道Jinja2模板中的流程控制:

    for

    Jinja2模板语言中的 for

    {% for foo in g %}
    {{ foo }}
    {% endfor %}

    if

    Jinja2模板语言中的 if

    {% if g %}
    
    {% elif g %}
        
    {% else %}
        
    {% endif %}

    接下来,我们对这几种情况分别进行传递,并在前端显示成表格

    字典

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

    后端demo.py

    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': 24, 'gender': ''}
    
    STUDENT_LIST = [
        {'name': '韩雪', 'age': 24, 'gender': ''},
        {'name': '舒畅', 'age': 23, 'gender': ''},
        {'name': '唐嫣', 'age': 25, 'gender': ''}
    ]
    
    STUDENT_DICT = {
        1: {'name': '韩雪', 'age': 24, 'gender': ''},
        2: {'name': '舒畅', 'age': 23, 'gender': ''},
        3: {'name': '唐嫣', 'age': 25, 'gender': ''},
    }
    
    @app.route("/student")
    def student():
        return render_template("student.html", student=STUDENT)
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)

    前端student.html

    <!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>
    View Code

    重新flask,访问页面

    从这个例子中,可以看出来,字典传入前端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': 24, 'gender': '女'}
    
    STUDENT_LIST = [
        {'name': '韩雪', 'age': 24, 'gender': '女'},
        {'name': '舒畅', 'age': 23, 'gender': '女'},
        {'name': '唐嫣', 'age': 25, 'gender': '女'}
    ]
    
    STUDENT_DICT = {
        1: {'name': '韩雪', 'age': 24, 'gender': '女'},
        2: {'name': '舒畅', 'age': 23, 'gender': '女'},
        3: {'name': '唐嫣', 'age': 25, 'gender': '女'},
    }
    
    @app.route("/student_list")
    def student_list():
        return render_template("student.html", student=STUDENT_LIST)
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    前端:

    <!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>
    View Code

    访问页面,注意:路径改了,效果如下:

    这里我们可以看出,如果是需要循环遍历的话,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>
    View Code

    访问页面,注意:路径改了,效果如下:

    大字典

    3.STUDENT_DICT 大字典传入前端 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': 24, 'gender': ''}
    
    STUDENT_LIST = [
        {'name': '韩雪', 'age': 24, 'gender': ''},
        {'name': '舒畅', 'age': 23, 'gender': ''},
        {'name': '唐嫣', 'age': 25, 'gender': ''}
    ]
    
    STUDENT_DICT = {
        1: {'name': '韩雪', 'age': 24, 'gender': ''},
        2: {'name': '舒畅', 'age': 23, 'gender': ''},
        3: {'name': '唐嫣', 'age': 25, 'gender': ''},
    }
    
    @app.route("/student_dict")
    def student_dict():
        return render_template("student.html", student=STUDENT_DICT)
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    前端:

    <!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>
    View Code

    在遍历字典的时候,foo 其实是相当于拿出了字典中的Key

    访问页面,注意:路径改了,效果如下:

     

    数据集合

    4.结合所有的字符串儿全部专递前端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': 24, 'gender': ''}
    
    STUDENT_LIST = [
        {'name': '韩雪', 'age': 24, 'gender': ''},
        {'name': '舒畅', 'age': 23, 'gender': ''},
        {'name': '唐嫣', 'age': 25, 'gender': ''}
    ]
    
    STUDENT_DICT = {
        1: {'name': '韩雪', 'age': 24, 'gender': ''},
        2: {'name': '舒畅', 'age': 23, 'gender': ''},
        3: {'name': '唐嫣', 'age': 25, 'gender': ''},
    }
    
    @app.route("/allstudent")
    def allstudent():
        return render_template("student.html", student=STUDENT,
                               student_list=STUDENT_LIST,
                               student_dict=STUDENT_DICT)
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    前端:

    <!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>
    View Code

    访问页面,注意:路径改了,效果如下:

    这里可以看出来,render_template中可以传递多个关键字

     **{}字典

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

    前端不变(标题4的前端代码)

    后端:

    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': 24, 'gender': ''}
    
    STUDENT_LIST = [
        {'name': '韩雪', 'age': 24, 'gender': ''},
        {'name': '舒畅', 'age': 23, 'gender': ''},
        {'name': '唐嫣', 'age': 25, 'gender': ''}
    ]
    
    STUDENT_DICT = {
        1: {'name': '韩雪', 'age': 24, 'gender': ''},
        2: {'name': '舒畅', 'age': 23, 'gender': ''},
        3: {'name': '唐嫣', 'age': 25, 'gender': ''},
    }
    
    @app.route("/allstudent")
    def allstudent():
        return render_template("student.html", **{"student": STUDENT,
                                                      "student_list": STUDENT_LIST,
                                                      "student_dict": STUDENT_DICT})
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    刷新页面,效果同上!

    Jinja2 的高阶用法

    Jinja2 模板语言为我们提供了很多功能接下来看一下它有什么高级的用法

    safe

    6.1. safe : 此时你与HTML只差一个 safe

    后端代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    
    app = Flask(__name__)
    
    @app.route("/")
    def index():
        tag = "<input type='text' name='user' value='xiao'>"
        return render_template("index.html",tag=tag)
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    在templates目录下新建文件index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        {{ tag }}
    
    </body>
    </html>
    View Code

    访问首页,效果如下:

    似乎和我们想要结果不太一样,有两种解决方案,

    第一种,从前端入手

    前端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        {{ tag|safe }}
    
    </body>
    </html>
    View Code

    刷新页面,效果如下:

    还有一种方式是从后端入手

    后端代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import Markup  # 导入 flask 中的 Markup 模块
    
    app = Flask(__name__)
    
    @app.route("/")
    def index():
        tag = "<input type='text' name='user' value='xiao'>"
        # Markup帮助咱们在HTML的标签上做了一层封装,让Jinja2模板语言知道这是一个安全的HTML标签
        markup_tag = Markup(tag)
        # <input type='text' name='user' value='DragonFire'> <class 'markupsafe.Markup'>
        print(markup_tag,type(markup_tag))
    
        return render_template("index.html", tag=markup_tag)
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    修改前端,还原代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        {{ tag }}
    
    </body>
    </html>
    View Code

    刷新页面,效果同上!

    执行Python函数

    模板中执行函数,首先在文件中定义一个函数

    后端代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    
    app = Flask(__name__)
    
    #定义一个函数,把它传递给前端
    def a_b_sum(a,b):
        return a+b
    
    @app.route("/")
    def index():
        return render_template("index.html", tag=a_b_sum)
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    前端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        {{ tag }}
        <br>
        {#传入2个参数#}
        {{ tag(99,1) }}
    
    </body>
    </html>
    View Code

    刷新页面,效果如下:

    看到结果就是,函数加()执行得到结果

    还可以定义全局函数,无需后端传递给前端,Jinja2直接就可以执行的函数

    后端代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    
    app = Flask(__name__)
    
    @app.template_global()  # 定义全局模板函数
    def a_b_sum(a, b):
        return a + b
    
    
    @app.template_filter()  # 定义全局模板函数
    def a_b_c_sum(a, b, c):
        return a + b + c
    
    
    @app.route("/")
    def index():
        return render_template("index.html", tag="")
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    前端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        {#函数#}
        {{ a_b_sum(99,1) }}
        <br>
        {#过滤器#}
        {{ 1 | a_b_c_sum(197,2) }}
    
    </body>
    </html>
    View Code

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

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

    刷新页面,效果如下:

    模板复用 block

    如果我们前端页面有大量重复页面,没必要每次都写,可以使用模板复用的方式复用模板

    前端代码:

    index.html 文件中的内容

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <h1>Welcome to My</h1>
        <h2>下面的内容是不一样的</h2>
        {% block content %}
    
        {% endblock %}
        <h2>上面的内容是不一样的,但是下面的内容是一样的</h2>
        <h1>My is Good</h1>
    
    </body>
    </html>
    View Code

    login.html 文件中的内容

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

    home.html 文件中的内容

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

    后端demo.py代码:

    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)
    View Code

    重启flask,访问登录页面:

    查看home页面

    大概是这样一个效果

    在这两个页面中,只有 block 中的内容发生了变化,其他的位置完全一样

    引用 include

    6.4 Jinja2模板语言的模块引用 include

    login.html 文件中的内容:

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

    index.html 文件中的内容

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <h1>Welcome to My</h1>
    
        {% include "login.html" %}
        <h2>上面的内容是不一样的,但是下面的内容是一样的</h2>
    
        <h1>My is Good</h1>
    
    </body>
    </html>
    View Code

    后端demo.py代码:

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    
    app = Flask(__name__)
    
    @app.route("/")
    def index():
        return render_template("index.html")
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    重启flask,访问页面:

    这就是将 login.html 当成一个模块,加载到 index.html 页面中

    五、用户登录例子

    做一个用户登录之后查看学员信息的小例子

    需求:

    • 1. 用户名: xiao 密码: 123
    • 2. 用户登录成功之后跳转到列表页面
    • 3. 失败有消息提示,重新登录
    • 4.点击学生名称之后,可以看到学生的详细信息

    后端

    demo.py

    from flask import Flask  # 导入Flask类
    from flask import render_template  # 导入flask中的render_template
    from flask import request
    from flask import redirect
    
    app = Flask(__name__)
    
    
    USER = {'username': 'xiao', 'password': "123"}
    
    STUDENT_DICT = {
        1: {'name': '韩雪', 'age': 24, 'gender': ''},
        2: {'name': '舒畅', 'age': 23, 'gender': ''},
        3: {'name': '唐嫣', 'age': 25, 'gender': ''},
    }
    
    app = Flask(__name__)
    
    # 只允许GET和POST请求
    @app.route("/login", methods=["GET", "POST"])
    def login():
        if request.method == "POST":
            if request.form["username"] == USER["username"] and request.form["password"] == USER["password"]:
                return redirect("/student_list")
            return render_template("login.html", msg="用户名密码错误")
    
        return render_template("login.html", msg="")  # 如果前端Jinja2模板中使用了msg,这里就算是传递""也要出现msg
    
    
    @app.route("/student_list")
    def student():  # 学生列表
        return render_template("student_list.html", student=STUDENT_DICT)
    
    
    @app.route("/info")
    def student_info():  # 学生的详细信息
        # 获取id
        stu_id = int(request.args["id"])
        stu_info = STUDENT_DICT[stu_id]
        return render_template("student.html", student=stu_info, stu_id=stu_id)
    
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 5000, debug=True)
    View Code

    前端

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form method="post">
            用户名:<input type="text" name="username">
            密码:<input type="text" name="password">
            <input type="submit" value="登录">
            {{ msg }}
        </form>
    </body>
    </html>
    View Code

    student_list.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <table border="2xp">
        <thead>
            <tr>
                <td>id</td>
                <td>name</td>
                <td>option</td>
            </tr>
        </thead>
        <tbody>
            {% for foo in student %}
                <tr>
                    <td>{{ foo }}</td>
                    <td>{{ student[foo].name }}</td>
                    <td><a href="/info?id={{ foo }}">详细</a></td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    </body>
    </html>
    View Code

    student.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <table border="1px">
        <thead>
        <tr>
            <td>id</td>
            <td>name</td>
            <td>age</td>
            <td>gender</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>{{ stu_id }}</td>
            <td>{{ student.name }}</td>
            <td>{{ student["age"] }}</td>
            <td>{{ student.get("gender") }}</td>
        </tr>
        </tbody>
    </table>
    <div><a href="/student_list">返回</a></div>
    </body>
    </html>
    View Code

    重启flask,访问登录页面

    登录之后,跳转到学生列表页面

    点击详细

     

    思考题:

    1.如果我直接访问 /student_list 和 /student 是不是也可以?

    2.怎么才能在所有的url地址中校验是否登录?

    本文参考链接:

    https://www.cnblogs.com/DragonFire/p/9260124.html

    六、内置Sessio

    Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪

    secret_key

    1. Flask 中 session 是需要 secret_key 的

    from flask import session
    app = Flask(__name__)
    app.secret_key = "ask"

    secret_key 实际上是用来加密字符串的,如果在实例化的app中没有 secret_key 那么开启session一定会抛异常的

    使用session

    2. session 要这样用

    @app.route("/login", methods=["GET", "POST"])
    def login():
        if request.method == "POST":
            if request.form["username"] == USER["username"] and request.form["password"] == USER["password"]:
                session["user"] = USER["username"]
                return redirect("/student_list")
            return render_template("login.html", msg="用户名密码错误")
    
        return render_template("login.html", msg="")  # 如果前端Jinja2模板中使用了msg,这里就算是传递""也要出现msg

    session["user"] = USER["username"] 这样用就代表这个请求带上来的session中保存了一个user=name
    如果想要验证session的话,就用这种方法吧

    cookies 中的 session 是什么

    3. cookies 中的 session 是什么

    cookies 中 session 存储的是通过 secret_key 加密后的 key , 通过这个 key 从flask程序的内存中找到用户对应的session信息

    session 验证

    4. 怎么用 session 进行验证呢?

    @app.route("/student_list")
    def student():
        if session.get("user"):
            return render_template("student_list.html", student=STUDENT_DICT)
    
        return redirect("/login")
  • 相关阅读:
    CODING x 百果园 _ 水果零售龙头迈出 DevOps 体系建设第一步
    Nocalhost 亮相 CD Foundation 国内首届 Meetup,Keith Chan 将出席致辞
    做云原生时代标准化工具,实现高效云上研发工作流
    打造数字化软件工厂 —— 一站式 DevOps 平台全景解读
    WePack —— 助力企业渐进式 DevOps 转型
    CODING Compass —— 打造行云流水般的软件工厂
    Nocalhost —— 让云原生开发回归原始而又简单
    CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全
    Nocalhost:云原生开发新体验
    使用 Nocalhost 开发 Kubernetes 中的 APISIX Ingress Controller
  • 原文地址:https://www.cnblogs.com/wxj1129549016/p/10233477.html
Copyright © 2011-2022 走看看