zoukankan      html  css  js  c++  java
  • Flask

    Python 现阶段三大主流Web框架 Django Tornado Flask 对比:

      Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架
      Flask 主要特点小而轻,原生组件几乎为0, 三方提供的组件请参考Django 非常全面,属于短小精悍型框架
      Tornado 优点是异步,用于游戏服务后台,缺点是干净,连个Session都不支持

      flask和django最大的不同点:request/session 是需要单独导入的

    flask知识点:

      - 模板+静态文件,app= Flask(__name__,....)
      - 路由 
        @app.route('/index',methods=["GET"])
      - 请求 
        request.form
        request.args
        request.method
      -响应
    
        render
        redirect
      -session
    
        session['xx'] = 123
        session.get('xx')

    Flask初级实现:

    from flask import Flask   #Flask是个类
    
    #传参实例化Flask,拿到一个对象app
    app = Flask(__name__)
    
    @app.route('/index')  #路由和下面函数绑定,@后面写上面实例化对象的名字
    #写一个函数,return一个结果
    def index():
        return "hello word-flask"
    
    #调用里面的run方法
    app.run()

     优化为:

    from flask import Flask   #Flask是个类
    
    #传参实例化Flask,拿到一个对象app
    app = Flask(__name__)
    
    @app.route('/index')  #路由和下面函数绑定,@后面写上面实例化对象的名字
    #写一个函数,return一个结果
    def index():
        return "hello word-flask"
    
    #调用里面的run方法
    if __name__ == '__main__':
        app.run()

    知识点一:用到的知识点有rsplit::切分 、getattr:返回对象属性值 、dir:返回模块的属性列表

    通过给定一个字符串路径,找到对应的类及类里面的属性和属性值

    例如:- 给你一个路径 “settings.Foo”,可以找到类并获取去其中的大写的静态字段。

    test.py里面的设置

    import importlib
    
    path = 'settings.Foo'
    p,c =path.rsplit('.',maxsplit=2)  #maxsplit代表切分几次
    # print(p,c) #settings Foo
    #拿到settings所在的路径
    m=importlib.import_module(p) #<module 'settings' from 'E:\知识点练习\知识点回忆\settings.py'>
    
    #getattr返回对象属性值
    cls=getattr(m,c)
    print(cls) #<class 'settings.Foo'>
    
    """例如下面:
    >>>class A(object):
    ...     bar = 1
    ... 
    >>> a = A()
    >>> getattr(a, 'bar')        # 获取属性 bar 值
    
    """
    #如何找到这个类
    #dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。
    # print(dir(cls)) #['DEBUG', '__class__', '__delattr__',...]
    for key in dir(cls):
        if key.isupper():
            #DEBUG True 最终拿到类中属性及属性值
            print(key,getattr(cls,key))
    根据字符路径找内容

    配置文件:查看、修改

    settings.py设置:设置配置文件参数

    #通过settings文件,完成对app.config配置文件的修改
    #分类,方便app里面不同的应用场景调用
    
    #共同需要的配置写在基类里面,下面单独修改的部分去继承这个基类
    class Config(object):
        DEBUG = False
        TESTING = False
        DATABASE_URI = 'sqlite://:memory:'
    
    # 开发环境
    class DevelopmentConfig(Config):
        DEBUG = True
    
    
    #上线环境
    class ProductionConfig(Config):
        DATABASE_URI = 'mysql://user@localhost/foo'
    
    
    class TestingConfig(Config):
        TESTING = True

    app.py配置:引用settings配置文件,实现查看、修改

    from flask import Flask,render_template,redirect,request
    
    app=Flask(__name__)
    
    #查看配置文件
    print(app.config)
    
    #修改配置文件
    #方式一:单独修改一项
    # app.config['DEBUG'] = True
    
    #方式二:批量修改,from_object后面是个字符串(根据字符串找到settings类,在类里面统一去做一些修改)
    app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类
    
    print(app.config)
    if __name__ == '__main__':
        app.run()

    路由系统:

    首先,要导入url_for: from flask import url_for

    近而,通过url_for反向生成url地址

    静态路由:无参数、反向解析endpoint

    @app.route('/index/123/456',methods=['GET','POST'],endpoint='n1')  #endpoint='n1'类似于Django里面的name,用于反向解析
    def index():
        # 通过url_for 反向生成url
        print(url_for('n1'))  #/index/123/456
        # 如果不指定endpoint='n1',默认写路由对应装饰的函数的名字
        print(url_for('index')) #/index/123/456
        
         user=session.get('user')
        # print(session)  session类似个字典(里面包含的用户名信息):    
        <SecureCookieSession {'user': 'yzz'}>
        if not user:
            return redirect('/login')
        return render_template('index.html')

    动态路由:有参数、也可以搭配反向解析使用

    #动态路由(<int:nid>)index要接收nid
    @app.route('/index/<int:nid>', methods=['GET', 'POST'])  # endpoint='n1'类似于Django里面的name,用于反向解析
    def index(nid):
        print(nid) #拿到的时你实际浏览器输入的值
        #url_for 有参数就传参数,没参数就写endpoint的值
        print(url_for('index',nid=733)) #/index/733
    
        user=session.get('user')
        # print(session)  session类似个字典(里面包含的用户名信息):<SecureCookieSession {'user': 'yzz'}>
        if not user:
            return redirect('/login')
        return render_template('index.html')

    FBV:

    请求与响应:

    #请求与响应
    # 请求相关信息
            request.method
            request.args
            request.form
            request.values
            request.cookies
            request.headers
            request.path
            request.full_path
            request.script_root
            request.url
            request.base_url
            request.url_root
            request.host_url
            request.host
            request.files
            obj = request.files['the_file_name']
            obj.save('/var/www/uploads/' + secure_filename(f.filename))
    
    # 响应:
            # 响应体:
            第一种:return “asdf”
            第二种:return jsonify({'k1': 'v1'})  #jsonify将字典转为字符串返回
            第三种:return render_template('xxx.html')
            第四种:return redirect()
    
    
            # 定制响应头:例如第一种方式
            obj = make_response("asdf")  #设置个响应体
            obj.headers['xxxxxxx'] = '123'  #设置个响应头 响应头里面会增加一项:xxxxxxx:123
            obj.set_cookie('key', 'value')   #设置cookies 响应头里面会增加一项:Set-Cookie:key=value; Path=/
            return obj

    实例:

    版本一:学生管理-简单登录、删除、查看

    from flask import Flask
    #导入三大组件:render_template模板渲染  redirect重定向
    from flask import render_template,request,redirect,session,url_for,jsonify,make_response
    
    app = Flask(__name__,template_folder="templates",static_folder="static") #默认后台文件夹的名字
    
    #需要加盐(因为flask的session是放在本地cookie里面的,只不过是加密),也可以添加在app.settings配置里面
    app.secret_key = 'fjsjflks'
    
    # 修改配置文件
    app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类
    
    
    STUDENT_DICT = {
        1:{'name':'张三','age':12,'gender':''},
        2:{'name': '李四', 'age': 34, 'gender': ''},
        3:{'name': '王五', 'age': 45, 'gender': ''},
    }
    
    #路由配置
    @app.route('/login',methods=['GET','POST'])
    def login():
        if request.method=="GET":
            # return 'login'
            return render_template('login.html')
    
        user = request.form.get('user')
        pwd = request.form.get('pwd')
        if user == 'yzz' and pwd == '123':
            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 render_template('index.html',stu_dic=STUDENT_DICT)
    
    @app.route('/delete/<int:nid>')  #接收前端点击,对应的nid,战队nid进行删除
    def delete(nid):
        user = session.get('user')
    
        if not user:
            # return redirect('/login')
            return redirect(url_for('login'))
    
        del STUDENT_DICT[nid]
        return redirect(url_for('index'))
    
    @app.route('/detail/<int:nid>')
    def detail(nid):
        user = session.get('user')
    
        if not user:
            return redirect('/login')
        info = STUDENT_DICT[nid]
        return render_template('detail.html',info=info)
    
    
    if __name__ == '__main__':
    
        app.run()
    主文件app.py
    <!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>
    登录lgin.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>
        <table border="1px">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>姓名</th>
                    <th>年龄</th>
                    <th>性别</th>
                    <th>选项</th>
                </tr>
            </thead>
    
            <tbody>
                {% for k,v in stu_dic.items()%}
                    <tr>
                        <td>{{k}}</td>
                        <td>{{v.name}}</td>
                        <td>{{v.age}}</td>
                        <td>{{v.gender}}</td>
                        <td>
                            <a href="/detail/{{k}}">查看详情</a> |
                            <a href="/delete/{{k}}">删除</a>
                        </td>
    
    
                    </tr>
                {%endfor%}
            </tbody>
    
    
    
        </table>
    
    </body>
    </html>
    学生信息一览index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>学生详情</title>
    </head>
    <body>
        {% for item in info.values()%}
            <li>{{item}}</li>
        {%endfor%}
    
    </body>
    </html>
    单个学生详情detail.html

    版本二:认证装饰器-基于functools模块(应用于比较少的函数中需要额外添加功能)

    from flask import Flask
    #导入三大组件:render_template模板渲染  redirect重定向
    from flask import render_template,request,redirect,session,url_for,jsonify,make_response
    
    app = Flask(__name__,template_folder="templates",static_folder="static") #默认后台文件夹的名字
    
    #需要加盐(因为flask的session是放在本地cookie里面的,只不过是加密),也可以添加在app.settings配置里面
    app.secret_key = 'fjsjflks'
    
    # 修改配置文件
    app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类
    
    
    STUDENT_DICT = {
        1:{'name':'张三','age':12,'gender':''},
        2:{'name': '李四', 'age': 34, 'gender': ''},
        3:{'name': '王五', 'age': 45, 'gender': ''},
    }
    
    #登录认证装饰器
    import functools
    def auth(func):
        @functools.wraps(func)
        def innder(*args,**kwargs):
            if not session.get('user'):
                return redirect(url_for('login'))
            ret = func(*args,**kwargs)
            return ret
        return innder
    
    
    #路由配置
    @app.route('/login',methods=['GET','POST'])
    def login():
        if request.method=="GET":
            # return 'login'
            return render_template('login.html')
    
        user = request.form.get('user')
        pwd = request.form.get('pwd')
        if user == 'yzz' and pwd == '123':
            session['user'] = user
            return redirect('/index')
    
        return render_template('login.html', error='用户名或密码错误')
    
    
    #静态路由(无参数)
    @app.route('/index')
    @auth
    def index():
    
        return render_template('index.html',stu_dic=STUDENT_DICT)
    print(index.__name__)
    
    @app.route('/delete/<int:nid>')  #接收前端点击,对应的nid,战队nid进行删除
    @auth
    def delete(nid):
    
        del STUDENT_DICT[nid]
        return redirect(url_for('index'))
    print(delete.__name__)
    
    @app.route('/detail/<int:nid>')
    @auth
    def detail(nid):
    
        info = STUDENT_DICT[nid]
        return render_template('detail.html',info=info)
    print(detail.__name__)
    
    if __name__ == '__main__':
    
        app.run()

    版本三:认证装饰器-基于@app.before_request(应用于需要装饰的方法较多时)

    @app.before_request
    def xxxx():
        if request.path == '/login':
            return None   #return None,表示允许通过,继续显示相应页面
        if session.get('user'):
            return None
    
        return redirect('/login')
    from flask import Flask
    #导入三大组件:render_template模板渲染  redirect重定向
    from flask import render_template,request,redirect,session,url_for,jsonify,make_response
    
    app = Flask(__name__,template_folder="templates",static_folder="static") #默认后台文件夹的名字
    
    #需要加盐(因为flask的session是放在本地cookie里面的,只不过是加密),也可以添加在app.settings配置里面
    app.secret_key = 'fjsjflks'
    
    # 修改配置文件
    app.config.from_object("settings.DevelopmentConfig")  #根据需求调用settings配置文件里面的类
    
    
    STUDENT_DICT = {
        1:{'name':'张三','age':12,'gender':''},
        2:{'name': '李四', 'age': 34, 'gender': ''},
        3:{'name': '王五', 'age': 45, 'gender': ''},
    }
    
    
    @app.before_request
    def xxxx():
        if request.path == '/login':
            return None   #return None,表示允许通过,继续显示相应页面
        if session.get('user'):
            return None
    
        return redirect('/login')
    
    
    #路由配置
    @app.route('/login',methods=['GET','POST'])
    def login():
        if request.method=="GET":
            # return 'login'
            return render_template('login.html')
    
        user = request.form.get('user')
        pwd = request.form.get('pwd')
        if user == 'yzz' and pwd == '123':
            session['user'] = user
            return redirect('/index')
    
        return render_template('login.html', error='用户名或密码错误')
    
    
    #静态路由(无参数)
    @app.route('/index')
    def index():
    
        return render_template('index.html',stu_dic=STUDENT_DICT)
    
    
    @app.route('/delete/<int:nid>')  #接收前端点击,对应的nid,战队nid进行删除
    def delete(nid):
    
        del STUDENT_DICT[nid]
        return redirect(url_for('index'))
    
    
    @app.route('/detail/<int:nid>')
    def detail(nid):
    
        info = STUDENT_DICT[nid]
        return render_template('detail.html',info=info)
    
    
    if __name__ == '__main__':
    
        app.run()
    app.py详细配置

    Flask中的三剑客:Render_template Redirect HttpResponse:

      HttpResponse:就是直接返回字符串

      Redirect:网页跳转重定向

      Render_template:使用时需要再主目录中加入一个templates 目录(否则会报一个jinjia2...的异常)

    Request:

    注意点:

      1.解释一个 @app.route("/req",methods=["POST"]) :
        methods=["POST"] 代表这个url地址只允许 POST 请求,是个列表也就是意味着可以允许多重请求方式,例如GET之类的
      2.Form表单中传递过来的值 使用 request.form 中拿到
      3.Flask 的 request 中给我们提供了一个 method 属性里面保存的就是前端的请求的方式

      4.request.args 与 request.form 的区别就是:
        request.args:是获取url中的参数
        request.form :是获取form表单中的参数
      5.request.values :只要是个参数我都要

      6.reuquest.cookies:将cookie信息读取出来

      7.request.headers:拿出请求头中的的秘密

      8.request.files:拿到的是你上传的文件

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

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

    request.files:

    html配置:
    <form method="post" action="" enctype="multipart/form-data"> #注意上传文件要配置enctype
    
        <p>用户名<input type="text" name="username"></p>
        <p>用户名<input type="password" name="password"></p>
        <p><input type="file" name="file"></p>
        <p><input type="submit" value="提交"></p>
        <p>
             {{ msg }}
        </p>
    
    
    </form>
    
    打印输出:
    print(request.files)
    验证结果:
    ImmutableMultiDict([('file', <FileStorage: '011.docx' ('application/vnd.openxmlformats-officedocument.wordprocessingml.document')>)])

    上面request其他的验证:

    from flask import Flask,render_template,redirect,request
    app=Flask(__name__)
    
    @app.route("/index")
    def index():
    
        print(request.args) #ImmutableMultiDict([('id', '1'), ('age', '30')])
        return "Hello Flask,Welcome you"
    
    
    @app.route("/login",methods=("POST","GET"))
    def login():
        if request.method == "POST":
    
            # 它看起来像是的Dict
            print(request.form)  #ImmutableMultiDict([('username', 'yzz'), ('password', 'yzz')])
            # print(request.form.keys())  #<dict_keyiterator object at 0x042FF5A0>
            # print(list(request.form.keys())) #['username', 'password']
    
    
            username=request.form.get('username') #yzz
            password=request.form.get('password')
            if username == 'yzz' and password == 'yzz':
                return redirect('/index')
            else:
                return render_template("template.html",msg="密码错误")
    
        return render_template("template.html", msg=None)
    app.run(debug=True)

    模板渲染:

    查看学生信息:就向后端传入字典、列表(套字典)、字典(套字典)

    from flask import Flask,render_template,redirect,request
    app=Flask(__name__)
    
    #格式一
    STUDENT = {'name': 'Old', 'age': 38, 'gender': ''},
    
    '''
    templates设置:
    return render_template("stu.html",student=STUDENT)
    路由函数设置:
    {{student}}
    
    '''
    
    #格式二
    STUDENT_LIST = [
        {'name': 'Old', 'age': 38, 'gender': ''},
        {'name': 'Boy', 'age': 73, 'gender': ''},
        {'name': 'EDU', 'age': 84, 'gender': ''}
    ]
    
    '''
    templates设置:
    <table border="1xp">
            {% for foo in student %}
                <tr>
                    <td>{{ foo.name }}</td>
                    <td>{{ foo.get("age") }}</td>
                    <td>{{ foo["gender"] }}</td>
                </tr>
            {% endfor %}
    </table>
    
    路由函数设置:
    return render_template("stu.html",student=STUDENT_LIST)
    
    '''
    
    #格式三
    STUDENT_DICT = {
        1: {'name': 'Old', 'age': 38, 'gender': ''},
        2: {'name': 'Boy', 'age': 73, 'gender': ''},
        3: {'name': 'EDU', 'age': 84, 'gender': ''},
    }
    '''
    templates设置:
    <table border="1xp">
            {% for k,v in student.items() %}
                <tr>
                    <td>{{ v.name }}</td>
                    <td>{{ v.get("age") }}</td>
                    <td>{{ v["gender"] }}</td>
                </tr>
            {% endfor %}
    </table>
    路由函数设置:
    return render_template("stu.html",student=STUDENT_DICT)
    
    '''

     return_template也可以传递多个值:

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

    Jinja2中的safe用法(xss攻击有关,如何显示html代码让浏览器识别定执行),结果输出就不是字符串,而是执行后的网页渲染效果

    正常网页显示结果:

      <input type='text' name='user' value='DragonFire'>  #普通字符串格式

    为了让浏览器能够识别并执行这个html代码,可以通过以下2中方式实现;

    方式一:前端加safe实现

    <body>
        <!--方式一:-->
        {{ tag | safe }}
    </body>

    方式二;后端导入Markup,实现

    from flask import Markup

    @app.route("/index")
    def index():
        #方式二:
        #导入Markup
        from flask import Markup
        tag = "<input type='text' name='user' value='DragonFire'>"
        markup_tag=Markup(tag)
    
        print(markup_tag,type(markup_tag)) #<input type='text' name='user' value='DragonFire'> <class 'markupsafe.Markup'>
    
        return render_template("index.html", tag=markup_tag)
  • 相关阅读:
    os模块
    函数练习
    集合 去重
    作业二:购物车程序
    作业一: 三级菜单
    字典练习
    字典
    切片
    冒泡练习
    判断整型数据奇偶数
  • 原文地址:https://www.cnblogs.com/yangzhizong/p/9744412.html
Copyright © 2011-2022 走看看