• Flask-2-路由


    前沿:处理URL和视图函数之间的绑定关系的程序就叫路由

    一、多个URL路由

    一个函数可以设置多个URL路由规则

    @app.route("/cases")
    @app.route("/cases/<case_id>")
    def get_case(case_id=None):
        if case_id is not None:
            return f"{case_id}"
        return "cases"
    

    这个例子接收两种URL,通过任何一个URL都可以走到这个视图函数里面

    • 访问localhost:5000/cases:则返回cases
    • 访问localhose:5000/case/432423,则返回432423

    注意

    1 、多个url可以绑定同一个视图函数,但是切记同一个url不能绑定在多个视图函数上

    2、如果还有其他的装饰器怎么处理?

    • 视图装饰器应该放最外层,否则里面的装饰器不会生效
    • 视图函数包裹的装饰器不要return其他信息,只要返回我们视图函数即可,否则会被包装程返回数据。
    def log_time(func):
        def swapper(*args, **kwargs):
            print(time.time())
            # 千万不要return其他值,否则会被包装成响应对象,返回到前端页面
            # return "自定义装饰器"
            return func(*args, **kwargs)
    
        return swapper
    
    
    @app.route("/interface/")
    @log_time
    def get_interface():
        return "interface"
        
    
    # 注意前面说的自定义的装饰要放在url注册装饰器的下面,
    # 如果位置换一下,你会发现自动义装饰器不会执行
    

    装饰器就是在视图函数外,处理一些公共的方法,比如储存访问的次数

    def set_count(func):
        def swapper(*args, **kwargs):
            app.config["num"]+=1
            return func(*args, **kwargs)
        return swapper
    

    二、路由的动态参数

    我们在设计url的时候,也可以设置成动态的url,前端通过url来传参给我们,不一定非要通过get,post请求传参

    只需要把动态的url放在<>中如:@app.route("/cases/<case_id>"),他可以把前端访问的url动态部分,传到视图函数中,视图函数需要设置一个参数接收即可

    @app.route("/cases/<case_id>")
    def get_case(case_id=None):
        if case_id is not None:
            return f"{case_id}"
        return "cases"
    

    动态url参数接收类型

    # int:整数
    @app.route("/cases/<int:case_id>")
    
    # float:小数
    @app.route("/cases/<float:case_id>")
    
    # string: 字符串,没有定义时默认类型
    @app.route("/cases/<case_id>")
    @app.route("/cases/<string:case_id>")
    
    # path:路径 /34/2233/4324/,可以/收尾,其他的不能
    @app.route("/cases/<path:case_id>")
    

    三、路由重定向

    比较访问,/index,和/index/ 两个路由之间的区别

    1、/index :我们访问/index/的时候不能访问成功,会报错404

    flask 哲学:当url 定义成/interface时, flask它会认为 /interface 和 /interface/ 是两个不同的url。
    定义的/interface,不能通过/interface/访问。

    2、/index/:我们定义这个时候,访问/index和/index/都能访问成功,但是两种是有区别的

    flask 为了灵活 有另外一种方式兼容:永久重定向。
    即:可以定义成/index/,此时 访问/index,flask没有找到,会告诉游览器,我找到了一个接近的 返回308,找到的url
    定义在location中,然后游览器在访问 location中的 /index/ ,返回200.

    3、为什么不进行这样的操作呢?

    唯一url原则

    • 从逻辑上来讲这样是不合理的,我们同样一个逻辑,你为什么要给两个地址?
    • 对SEO有好处,两个url会被搜索两次,重复内容会被降权
    • 到底后面加“/”,还是不加呢?加可以兼容,不加就报错,根据自己实际需求处理就好,我通常是不加的

    四、路由注册机制

    访问URL执法对应的视图函数,函数是没有主动调用的,在哪里使用的呢?

    之前我们最小原型实例中,优化后我们是把url和函数处理逻辑映射到字典中保存,其实flask也是这一套操作

    flask其实提供了两种方式注册路由

    1、装饰器:@app.route("/")

    @app.route("/")
    def index():
        pass
    

    2、集中注册:app.add_url_rule()

    
    def get_case_list():
        return "case_list"
    
    app.add_url_rule("/case_list", view_func=get_case_list)
    

    3、源码阅读

    其实我们看route()方法源码,也可以发现也是调用app.add_url_rule(),只是flask帮我实现了装饰器,在中小型项目中更加优雅方便

    而url和视图的映射关系(通过端点-下面有提到)都是保存在url_map里面

    4、装饰器VS集中注册

    装饰器更加优雅,看起来更加清晰,url和视图函数关系明确,非常适合中小型项目

    集中注册,更加灵活,把所有的url路由都定义到了一起,当某一个路由出现出现问题的适合,很快就能找到改路由,不能到各个视图函数文件中找,适合中大型项目

    提示:其实falsk提供的所有装饰器,都有对应的集中注册方法,后续降到模板引擎用的和请求钩子等都可以采用集中方式,这里大家有个印象即可,后续分享到对应内容在具体说明

    五、app.route()可配置参数

    app.route()的option参数是用了werkzeug的Rule类

    有很多参数可配置,也是我们经常会用的

    我们主要掌握其中几个重点经常用的参数即可,其他如有需求,请自行阅读源码的参数说明进行使用

    1、endpoint:端点

    可以理解为url和视图函数绑定关系的命名,默认是None,flask会取视图函数的名称定义关系名,也可以自定义

    进行URL构建的时候会用url_for(endpoint),endpoint的主要作用是在url和视图函数中间设置一个桥梁,通过这个endpoint就能找到对应的url和视图函数

    @app.route("/home", endpoint="get_home_1")
    def get_home():
        return "home"
    
    print(app.url_map())
    
    

    2、methods:请求方法

    默认没有设置的时候,仅支持GET、HEAD、OPTIONS
    我们就通过这个参数来限制前端的接口的访问方法

    # 定义post请求方法,前端访问只能用post方法请求
    @app.route("/login/<username>", methods=["POST"])
    def login(username=None):
        if username is None:
            return "请输入用户名"
        return "登录成功"
    

    3、redirect_to:重定向

    我们在使用重定向的时候其实是有两种方式的,一是用redirect_to关键字参数,二是用redirect()方法实现。

    两种究竟有何不同呢?

    一、redirect_to关键字参数

    使用关键字参数重定向到其他路由的时候,本视图函数的逻辑是不会执行的,只会执行重定向的路由的视图函数逻辑

    @app.route("/cases/<path:case_id>")
    def get_case(case_id=None):
        if case_id is not None:
            print(type(case_id))
            return f"{case_id}"
        return "cases"
        
    # 当时定义参数redirect_to 参数时,访问"/" 不在返回index,返回重定向的路由case_id
    @app.route("/",methods=["GET"],redirect_to="/cases/4444")
    def index():
        print("关键字参数重定向内部逻辑")
        return "index"
    

    二、redirec():方法

    flask给我给提供了重定向其他路由的方法,接收url参数即可。

    但是url这种参数有可能会变,而url和视图函数之间的绑定关系一般是不变的,也就是端点一般是不变的,所以redirect()方法配合url_for(endpoind)使用

    1)url_for()

    一般重定向的时候组合使用,url_for方法,传入端点名,它里面就帮我们实现了,通过端点找到url,而且还支持传关键字参数,假如重定向到interface接口时,需要一个关键字参数id=3,可以直接redirect(url_for("interface",id=3))当然直接使用url在url后面加?id=3 也可行

    2)参数说明

    endpoint:端点(默认函数的名字)

    **values:URL的关键字参数

    _external:如果设置为True,则生成一个绝对路径URL

    _scheme:一个字符串指定所需的URL方案。_external参数必须设置为True,不然会抛出ValueError。

    _anchor:如果设置了这个则给URL添加一个mao

    _method: 如果设置这个则显示地调用这个HTTP方法

    3)redirect+url_for案例

    @app.route("/interface/")
    def get_interface():
        return "interface"
        
    
    # 方式二,在视图函数内处理完逻辑在重定向
    @app.route("/home")
    def get_home():
        print("函数内部逻辑")
        # 得到完整的url,并且请求参数id=3
        print(url_for("get_home_1", _external=True, id=3))
        return redirect(url_for("get_interface", id=3))
    

    4、defaults:参数默认值

    定义默认参数,可以在视图函数中接收,defaults={"id":2}

    也可以直接在视图函数中定义默认值参数def interface(id=2) ---更方便

    @app.route("/cases/<case_id>")
    def get_case(case_id):
        return f"{case_id}"
    

    如果我们请求的时候不传case_id 就会报错

    怎么才能调整他不报错呢?

    我们只要给路由增加一个defaults默认值即可

    @app.route("/cases/", defaults={"case_id": 3})
    @app.route("/cases/<case_id>")
    def get_case(case_id):
        return f"{case_id}"
    

    我们也可以不同这个参数,可以直接在视图函数中定义参数的给默认值即可--更方便

    @app.route("/cases/")
    @app.route("/cases/<case_id>")
    def get_case(case_id=3):
        return f"{case_id}"
    

    六、视图函数的分离(大型项目)

    随着项目的增大,我们想要把视图函数放在一起,视图函数,app、url不写在一个文件里的,所以我们的架构变成了

    • 启动文件:仅仅初始化app,配置信息,启动服务
    • 视图函数:接收请求,处理数据、响应结果
    • url集中注册:url和视图绑定
    • 数据处理:为视图函数服务,被视图函数调用
    • templates:html页面
    • static:静态文件如js,css
    • 其他的帮助函数:其他公共方法
    # viewfunction.py 视图函数py文件
    
    # form model层的数据处理方法
    # 首页
    def home():
        # 接收请求数据
        # 处理数据
        return "home page"
    
    
    # cases页
    def cases():
        return "case page"
    
    # urls.py
    # 导入app对象、导入视图函数,进行集中对象
    #
    
    from flask_main import app
    import viewfunction as views
    
    # 注册路由
    app.add_url_rule("/", view_func=views.home)
    app.add_url_rule("/cases", view_func=views.cases)
    
    # flask_main.py
    # 主要时初始化app,处理配置信息,开启服务即可
    # 接下来导入urls.py注册的路由即可
    
    from flask import Flask
    
    # from flask_frame.Flask_views.urls import *  # 直接引用会导致循环导入
    
    app = Flask(__name__)
    app.config["DEBUG"] = True
    
    # 只能在哪里用的时候在导入
    from flask_frame.Flask_route.flask_fenceng.urls import *
    
    if __name__ == '__main__':
        app.run(debug=app.config.get("DEBUG"))
    

    上述只简单的分了视图、url、app分离,还有具体model层和其他公共方法之类根据业务实际分层即可

    这样我们主入口功能其实非常明确的,也非常的简单

    注意

    不知道大家注意到没有?在我们的urls层需要到flask.main文件的app 来注册路由,而falsk.mian里面又需要加载urls层注册的路由,然后开启的服务才能加载上这些路由。

    两个文件之间互相导入,肯定会导致循环导入的情况发生。

    所以为了避免循环导入我们只能像案例中的那样,哪里用就在哪里导入,没必要非要遵守PEP8规范。其实很多三方框架都是这么处理,包括falsk也用过这种导入

  • 相关阅读:
    hihocoder #1388 : Periodic Signal NTT&FFT
    HDU 5895 Mathematician QSC(矩阵乘法+循环节降幂+除法取模小技巧+快速幂)
    hdu 5894 hannnnah_j’s Biological Test 组合数学
    csu 1812: 三角形和矩形 凸包
    地铁 Dijkstra(优先队列优化) 湖南省第12届省赛
    后缀自动机专题
    数学渣的自我修养!!!
    高斯消元(浮点)
    The PLAN
    ccpc网络赛
  • 原文地址:https://www.cnblogs.com/jiangmingbai/p/13089947.html
Copyright © 2020-2023  润新知