Flask路由

1.路由

1.1路由使用

1.1.1 @app.route()
# @app.route() 简单使用
# @app.route(url路由),这个调用路由要写在对应视图函数上访
@app.route("/")
def index():
    return "HelloWord!"
# route()源码
def route(self, rule: str, **options: t.Any) -> t.Callable:
    """
    # 装饰一个视图函数,用给定的URL注册它规则和选项。调用'add_url_rule'(其中包含更多内容关于实现的详细信息)
    	Decorate a view function to register it with the given URL
        rule and options. Calls :meth:`add_url_rule`, which has more
        details about the implemenstation.

    # 如果'endpoint'参数没有传值,路由的端点名称默认为视图的名称函数
        The endpoint name for the route defaults to the name of the view
        function if the ``endpoint`` parameter isn't passed.
        
    # 'methods'参数默认为["GET"],HEAD' 和'OPTIONS'会自动添加。如果想要其他请求就在methods=["GET","POST","XXX".....]
        The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and
        ``OPTIONS`` are added automatically.
        
    # rule:url规则字符串
        :param rule: The URL rule string.  
        
    # options:额外选项传给werkzeug.routing.Rule对象
        :param options: Extra options passed to the
            :class:`~werkzeug.routing.Rule` object.  
        """

    def decorator(f: t.Callable) -> t.Callable:
        endpoint = options.pop("endpoint", None)  # 从options字典中删除并获取endpoint的值,有endpoint就返回对应的值,没有就是接收None
        self.add_url_rule(rule, endpoint, f, **options)   # add_url_rule()才是route的核心
        return f

    return decorator  # 调用route,返回内部函数地址,route是一个装饰器,它的主要作用在decorator函数内
1.1.2 app.add_url_rule()
# app.add_url_rule() 简单使用
# app.add_url_rule(URL路由,endpoint=None,view_func=视图函数名)
def index():
    return "HelloWord!"
app.add_url_route("/",view_func=index)  # 路由url:/ 与 视图函数index 绑定
# add_url_route 源码
    def add_url_rule(
        self,
        rule: str,
        endpoint: t.Optional[str] = None,
        view_func: t.Optional[t.Callable] = None,
        provide_automatic_options: t.Optional[bool] = None,
        **options: t.Any,
    ) -> None:
        # 如果没有传递'endpoint'参数,就把 视图函数的名称 传给 路由的端点名称。
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)  # type: ignore
        options["endpoint"] = endpoint
        methods = options.pop("methods", None)
        
        # 1.判断method是否为None,如果为None,
        # 2.使用反射getattr 去view_func去找methods属性值,如果view_func.metods存在 就把其值返回传给method,or后面就不用看,不存在返回的是None,就把or后面的("GET",)元组返回给method
        if methods is None:
            methods = getattr(view_func, "methods", None) or ("GET",)
        # 判断 methods 是否为字符串,
        if isinstance(methods, str):
            raise TypeError(
                "Allowed methods must be a list of strings, for"
                ' example: @app.route(..., methods=["POST"])'
            )
        # 把methods里面的请求方法变为大写,并且methods是集合自带去重
        methods = {item.upper() for item in methods}

        # Methods that should always be added (应该始终添加的方法)
        # 如果view_func有required_methods属性,并把view_func.required_methods的值传回 并由set变成一个集合
        required_methods = set(getattr(view_func, "required_methods", ()))

        # 从Flask 0.8开始,view_func对象可以禁用和强制启用自动选项处理。
        # 如果provide_automatic_options没有传参,就去view_func查找provide_automatic_options属性值,有值拿出并返回,没有返回None
        if provide_automatic_options is None:
            provide_automatic_options = getattr(
                view_func, "provide_automatic_options", None
            )
	
        # 判断 从view_func中provide_automatic_options是否为None
        if provide_automatic_options is None:
            # 判断 methods集合中是否有"OPTIONS"请求方法,
            #没有就把"OPTIONS"加入required_methods集合中,并把provide_automatic_options开启
            #有"OPTIONS",就把provide_automatic_options关闭
            if "OPTIONS" not in methods:  
                provide_automatic_options = True  
                required_methods.add("OPTIONS")
            else:
                provide_automatic_options = False

        # 把请求方式综合到一块,集合method 和 集合required_methods 并集,并把结果集 赋值给methods
        methods |= required_methods

        # 创建rule并初始化url_rule_class对象
        rule = self.url_rule_class(rule, methods=methods, **options)
        rule.provide_automatic_options = provide_automatic_options  # type: ignore

        # 把是上面实例化的路由对象 加载到 url_map(app的url路由映射里面)
        self.url_map.add(rule)
        if view_func is not None:
            # 获取 视图函数的端点名
            old_func = self.view_functions.get(endpoint)
            # 视图函数的端点名有值(非None)且 端点名 和 视图函数名 不一样,就报错
            if old_func is not None and old_func != view_func:
                raise AssertionError(
                    "View function mapping is overwriting an existing"
                    f" endpoint function: {endpoint}"
                )
            # 视图函数的端点名为NOne,就把 视图函数名 传给 端点
            self.view_functions[endpoint] = view_func

1.1.3总结
  • 1.route()装饰器本质上还是 调用 add_url_rule()

    """
                @app.route("/")
                def index():
                    ...
                    
                    /\
                   /||\
                    ||
                  上下两者等价
                    ||
                   \||/
                    \/
                    
                def index():
                    ...
                app.add_url_rule("/", view_func=index)
    """
    
  • 2.如果rule规则参与路由的端点名称(某个视图函数必须被某个端点相关联("endpoint"装饰器装饰)),'view_func'不一定需要传参

    app.add_url_rule("/", endpoint="index")
    @app.endpoint("index")
    def index():
        ...   
    
  • 3.路由视图函数上加自写装饰器,需要在装饰器中调用@wraps(接收的外部函数名的形参名)

    在flask中路由,url与视图函数的映射,实际是就是通过 endpoint 关联起来的。
    如果'endpoint'参数没有传值,路由的端点名称默认为视图的名称函数(内部操作最终默认即为view_func.__name__),如果传参,还要保证传的参数名字 和 传的view_func函数名值一样。通俗讲就是 不管怎样 endpoint 和 view_func.__name__名字一样。
    在项目后期,如果给视图函数加上自写的装饰器,有可能会导致该视图函数view_func.__name__值发生变化,从而导致视图函数重复
    # 例如:
    #1.不加装饰器 
    @app.route("/")
    def home():
        return "你好"
    print(home.__name__)  # home.__name__的值为 home
    
    # 2.加上装饰器 
    def login_decorator(func):
        def wrapper(*args,**kwargs):
            ....  # 这里写验证是否已登录相关代码
            return fun(*args,**kwargs)
        return wrapper
    @login_decorator
    @app.route("/")
    def home():
        return "你好"
    print(home.__name__)  # home.__name__的值为 wrapper
    
    
    # 3.加上装饰器里面写上 wraps装饰器
    def login_decorator(func):
        @wraps(func)  # 本质就是wrapper.__name__=func.__name__ 
        def wrapper(*args,**kwargs):
            ....  # 这里写验证是否已登录相关代码
            return fun(*args,**kwargs)
        # wrapper.__name__=func.__name__ 
        return wrapper
    @login_decorator
    @app.route("/")
    def home():
        return "你好"
    print(home.__name__)  # home.__name__的值为 home
    

1.2查看路由信息

1.2.1 在终端以命令行的方式:
①首先需要通过加载FLASK_APP环境变量告诉你的终端要查看谁的应用程序路由(把你要运行的app实例文件名传给FLASK_APP,详情参考终端启动加载FLASK_APP环境变量
# 在linux终端
export FLASK_APP=hello

# 在win的cmd终端窗口
set FLASK_APP=hello

# 在win的Powershell窗口(在pycharm中的Terminal窗口,pycharm版本不是很老的话,一般默认都是Powershell)
$env:FLASK_APP = "hello"

# 参数说明:
FLASK_APP=xxxx 亦或 FLASK_APP = "xxxx"  其中xxxx表示APP实例文件名 ,上面写的hello就是创建APP实例文件名

# 上面中hello实例文件 创建详情 点击上面 详情参考
②命令行输入:flask routes,但是flask routes 获取的路由信息不是很全
# 输入:flask routes
# 得到类似下面结果:

(端点)     (请求方法) (路由规则)
Endpoint     Methods   Rule
-----------  -------  -----------------------
hello_world  GET      /
static       GET      /static/<path:filename>

endpoint:端点,视图函数名的字符串形式;
methods:请求方法;
rule:路径规则;
static是Flask框架帮我们默认创建的静态路由,方便静态文件的访问

1.2.2 在程序中获取

①在应用中的url_map属性中保存着整个Flask应用的路由映射信息,可以通过读取这个属性获取全部路由信息
# 1.在app实例文件里面写上如下:
print(app.url_map)
# 2.运行该app实例文件,得到结果如下:
Map([<Rule '/' (HEAD, GET, OPTIONS) -> hello_world>,
 <Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
map:表示路由映射,容器列表;
python中<>存储的信息,一般表示对象;
Rule:路径规则,存储了url的路径名、http请求方法、端点(视图函数名)

1.3 通过ipython和应用程序进行交互(这里通过pycharm里面的Python Console窗口进行交互,如下图所示),在app.app_context()设置一个应用程序上下文current_app.url_map来获取路由信息。

# 输入以下命令:
from hello import app  # hello是 实例app文件,从hello导出app实例对象
with app.app_context():  # 应用上下文配置
	from flask import current_app
	print(current_app.url_map)  # 查看路由信息
    
# 得到结果如下:
Map([<Rule '/' (HEAD, GET, OPTIONS) -> hello_world>,
 <Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])

posted @   流走在黑夜深巷的猫  阅读(140)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示