• Flask(1):基本示例、配置文件、路由、请求和响应、模板渲染


    Flask的特点:

    - pip install flask 
    - 短小精悍、可扩展性强的 web框架
        注意:上下文管理机制
    - 依赖 wsgi:werkzeug

    Flask的简单示例:

    from flask import Flask
    # app = Flask(__name__,template_folder="templates",static_folder="static",static_url_path="/vvv")  # template_folder(默认为 templates )、static_folder(默认为static)都是在这里设置;static_url_path="/vvv":设置静态文件的路径(给静态文件statci的路径设置一个别名;用在模板中)
    app = Flask(__name__)
    
    @app.route("/index")  # 装饰器表示 路径和函数 绑定
    def index():
        return "hello world"
    
    if __name__ == "__main__":
        app.run()  # 启动 socket

    Flask登陆示例:

    目录结构:

    project
    |-- static
        |-- 1.png
    |-- templates
        |-- index.txt
        |-- login.html
    |-- flask_login.py

    flask_login.py

    from flask import Flask,request,render_template,redirect,session
    
    app = Flask(__name__)
    app.secret_key = "nbaoireunbadfo"  # 设置session的时候,需要加盐加密
    
    @app.route("/login",methods=["GET","POST"])
    def login():
        if request.method == "GET":
            return render_template("login.html")
    
        username = request.form.get("username")
        password = request.form.get("psw")
        if username == "neo" and password == "abc123":
            session["user"] = username  # 设置 session
            return redirect("/index")
        else:
            return render_template("login.html", error="用户名密码错误") # 传递参数也可用字典
    
    @app.route("/index")
    def index():
        # 登陆之后才能访问 index 页面
        if not session.get("user"):  # 获取 session
            return redirect("/login")
        return render_template("index.txt")  # 模板后缀不影响
    
    if __name__ == "__main__":
        app.run()
    
    """
    小结:
    from flask import request  # Flask 的请求数据是这样导入的,不是像Django 那样通过参数传递的
    
    from flask import render_template  # 渲染的模板
    render_template(模板名,**{"传递的参数":传递的参数})
    
    from flask import redirect # 重定向
    
    from flask import session # session;flask中session默认是以加密的方式保存在了用户浏览器的cookie中;所以要设置加盐(加密)
    app.secret_key = "apiofdgqpweu"  # session 加密加盐
    
    request.methods # 获取请求方式
    request.args  # 获取 GET 请求的数据,对应 Django 的request.GET (url里面传过来的参数)
    request.form  # 获取 POST 提交过来的数据,对应Django的 request.POST(请求体里面传过来的参数)
    
    @app.route("/login",methods=["GET","POST"])  # methods=["GET","POST"] 表示可接收GET和POST请求,默认只接收GET
    # 默认的 模板文件夹叫 templates;默认的静态文件叫 static
    
    # <form>表单只能发送 get 和 post请求,patch 和 delete请求要通过 Ajax发送
    """

    templates/index.txt

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h3>欢迎登陆</h3>
        <img src="/static/1.png" alt="">  # src 中的 /static 可更改,通过 static_url_path 设置
    </body>
    </html>

    templates/login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <form action="" method="post">
        <input type="text" name="username">
        <input type="password" name="psw">
        <input type="submit" value="提交"> <span>{{error}}</span>
        <!-- {{ }} 用于传递参数 -->
    </form>
    
    </body>
    </html>

    配置文件:

    # 通过字符串找到类中的静态字段,如 "settings.Foo" 中的静态字段

    # 通过字符串找到类中的静态字段,如 "settings.Foo" 中的静态字段
    import importlib
    path = "settings.Foo"
    module_path,class_name = path.rsplit(".",1)
    module = importlib.import_module(module_path)
    cls = getattr(module,class_name)
    
    for key in dir(cls):  # dir(cls) :返回一个列表,其中包含静态字段
        if key.isupper():  # 静态字段得是大写
            print(key,getattr(cls,key))  # 获取静态字段及对应的值

    设置配置文件:

    # settings.py
    class Config(object): 共用的配置信息
        TESTING = False
    
    class ProductionConfig(Config): 生产环境下的配置
        DEBUG = False
        
    class DevelopmentConfig(Config):
        DEBUG = True
        
    
    # app.py
    from flask import Flask
    
    app = Flask(__name__)
    # app.config  # 获取 Flask 的 配置文件  # 配置文件中的字段必须得是 全大写
    # app.config.from_object("python类或类的路径")  # 设置配置文件
    # 也可以这样单独设置配置信息:
    # app.config["DEBUG"] = True
    
    app.config.from_object("settings.DevelopmentConfig")  
    
    if __name__ == "__main__":
        app.run()

    其它配置:

    flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
        {
            'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
            'TESTING':                              False,                          是否开启测试模式
            'PROPAGATE_EXCEPTIONS':                 None,                          
            'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
            'SECRET_KEY':                           None,   # session 相关(加盐加密)
            'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
            'USE_X_SENDFILE':                       False,
            'LOGGER_NAME':                          None,
            'LOGGER_HANDLER_POLICY':               'always',
            'SERVER_NAME':                          None,
            'APPLICATION_ROOT':                     None,
            '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,
            'MAX_CONTENT_LENGTH':                   None,
            'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
            'TRAP_BAD_REQUEST_ERRORS':              False,
            'TRAP_HTTP_EXCEPTIONS':                 False,
            'EXPLAIN_TEMPLATE_LOADING':             False,
            'PREFERRED_URL_SCHEME':                 'http',
            'JSON_AS_ASCII':                        True,
            'JSON_SORT_KEYS':                       True,
            'JSONIFY_PRETTYPRINT_REGULAR':          True,
            'JSONIFY_MIMETYPE':                     'application/json',
            'TEMPLATES_AUTO_RELOAD':                None,
        }

    路由系统

    @app.route() 这个路由中的参数 endpoint="xx" :给该视图函数起一个别名(相当于django url中的name),如果 endpoint不写,默认是函数名;通过别名反解路径: url_for("xx") , url_for 需要导入
    
    # 路由的动态传参
    @app.route("/index/<int:nid>",method=["GET","POST"],endpoint="url1")  # 路由中传参时,视图函数中需要接收一下;如果 int 不写,则默认是字符串格式; 
    def index(nid):  # 接收参数
        print(url_for("url1",nid=777))  # 反解路径时,如果url中动态传参了,需要在后面指定传的参数
        return "Index"
        
    # 动态传参时的类型包括:string,int,float 和 path; 如果不指定,默认是 string

    请求和响应 

    from flask import Flask,request,render_template,redirect,make_response
    
    # ...(省略)
    
    @app.route("/login",methods=["GET","POST"])
    def login():
        """
        请求相关信息:
        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(obj.filename)) # 保存文件
        """
        """
        响应相关信息:
        1. 响应体:
        return "字符串"
        return jsonify(xxx)  # 返回 json 数据; jsonify 需要从 flask导入
        return render_template(模板)
        return redirect() # 重定向
        上面4个返回的都是响应体(都是以响应体的方式返回)
        
        2. 定制响应头(以 return "字符串" 为例):
        obj = make_response("Index")  # make_response(你想要返回的内容); make_response() 能把你想要返回的内容进行封装到一个对象中; make_response 需要从 flask导入
        obj.headers["xxx"] = "abc"  # 设置响应头
        return obj  # 返回响应对象
        
        3. 设置 cookie
        obj = make_response(render_template("index.html"))
        obj.set_cookie("key","value")  # 设置cookie  # cookie 是随着响应头给用户的
        obj.delete_cookie("key")  # 删除 cookie
        return obj
        
        """
        # ...(省略)

    模板渲染

    python代码:

    # 下面的字典模拟数据库
    STU_DICT = {
        1:{"name":"neo","age":22,"gender","male"},
        2:{"name":"maple","age":35,"gender","male"},
        3:{"name":"conan","age":12,"gender","male"},
    }
    
    # index 函数
    @app.route("/index")
    def index():
        return render_template("index.html",stu_dict=STU_DICT)  # 渲染模板时,传入要渲染的参数
        

    对应的模板:

    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
            </tr>
        </thead>
        
        <tbody>
            <!-- Flask 渲染模板时,用到的python函数需要加括号“()”;Django不需要 -->
            {% for k,v in stu_dict.items() %}  
                <tr>{{k}}</tr>
                <!-- 可以用 .name 的方式 来取值;和Django的用法一样 -->
                <tr>{{v.name}}</tr>  
                <!-- 可以用 v["age"] 的这种字典的方式 来取值 -->
                <tr>{{v["age"]}}</tr> 
                <!-- 也可以用 v.get("gender","female") 的这种字典的方式 来取值; .get() 的时候也可设置默认值  -->
                <tr>{{v.get("gender")}}</tr> 
            {% endfor %}
        </tbody>
    
    </table>

    其它模板渲染的方法:

    tpl_render.py

    from flask import Flask,render_template,Markup
    
    app = Flask(__name__)
    
    def func(arg):
        return arg + 1
    
    @app.template_global()  # 如果某个函数在全局好多模板中都需要用到,为了避免多次传递这个函数,可以使用template_global()这个装饰器装饰该函数(该装饰器需要加() ),然后这个函数就能在全局所有模板中直接使用
    def foo_global(a,b):
        # 使用方法:{{foo_global(2,3)}}
        return a + b
    
    @app.template_filter()  # template_filter() 装饰的函数也能在全局(该装饰器需要加 ()),只是这个被装饰的函数 能用在前端的 if等语句中
    def foo_filter(a,b,c):
        # 使用方法:
        return a + b + c
    
    
    @app.route("/tpl")
    def tpl():
        context = {
            "user":["neo","maple"],
            "txt1":'<input type="text">',
            "txt2": '<input type="text">',
            "txt3": Markup('<input type="text">'), # HTML标签字符串也可以在后端 Markup(),从而让其在前端展示为 HTML标签
            "func":func,  # 也可以往前端传递一个函数;Flask传递函数时在前端不会自动执行,得自己调用(Django传递函数会自动执行)
        }
    
        return render_template("tpl.html",**context)  # 可以通过 **context 的方式传参
    
    if __name__ == "__main__":
        app.run()

    tpl.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!-- 和Django的用法一样,Flask也可以:list.索引;user是["neo","maple"]这个列表 -->
        {{user.0}}
        <!-- python语法也能在 Flask 中直接用:list[索引] -->
        {{user[0]}}
        <!-- {{txt1}}是字符串;Flask自动将 html 标签字符串做了处理 -->
        {{txt1}}
        <!-- 如果想让 HTML 标签字符串 变成HTML标签,可以在前端 |safe  -->
        {{txt2|safe}}
        <!-- HTML标签字符串也可以在后端 Markup(),从而让其在前端展示为 HTML标签 -->
        {{txt3}}
        <!--传递函数-->
        {{func(2)}}
        <!-- template_global() 装饰的函数能在全局模板直接使用 -->
        {{foo_global(2,3)}}
        <!-- template_global() 装饰的函数能在全局模板直接使用,{{1|foo_filter(2,3)}} :a是1,b是2,c为3 -->
        {{1|foo_filter(2,3)}}
    
        <!--宏定义-->
        <!-- macro 是宏定义的语法(相当于函数定义的 def );input是宏定义的函数名(可随便改);type="text"表示type默认为"text",value="" 表示 value默认为空 -->
        {% macro input(name,type="text",value="") %}
            <h2>宏定义</h2>
            <input type="{{type}}" name="{{name}}" value="{{value}}">
        {% endmacro %}
    
        <!--宏定义的函数不会自动执行,需要调用,如下-->
        {{input("neo")}}
    
        <!--
        此外, Flask 的 模板继承 和 include 的使用方法 和 Django 一样,不再重复
        -->
    </body>
    </html>
  • 相关阅读:
    Solution -「HEOI/TJOI 2016」「洛谷 P2824」排序
    Solution -「国家集训队」「洛谷 P2839」Middle
    Solution -「CTSC 2018」「洛谷 P4602」混合果汁
    Solution -「CF 793G」Oleg and Chess
    Solution -「AGC 019F」「AT 2705」Yes or No
    Solution -「AGC 013E」「AT 2371」Placing Squares
    使用Spock 单元测试
    Sentinel 熔断等指标如何统计以及如何判断熔断点
    牛客多校第五场自闭
    (单调栈)Largest Rectangle in a Histogram
  • 原文地址:https://www.cnblogs.com/neozheng/p/9756024.html
Copyright © 2020-2023  润新知