欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Django3.2 自动发现所有路由代码详解

程序员文章站 2024-01-02 23:53:46
目录1.需求2.代码实现总结1.需求发现项目本地所有带别名的url,组成一个有序字典,方便后续调用;定向排除部分url,如django自带的 admin下的路由;2.代码实现import re...

1.需求

发现项目本地所有带别名的url,组成一个有序字典,方便后续调用;
定向排除部分url,如django自带的 admin下的路由;

2.代码实现

import re              # 正则
from collections import ordereddict      # 创建有序字典
from django.conf import settings          # 导入setting配置文件(获取项目根路径urls.py)
from django.utils.module_loading import import_string      # 字符串导入模块
from django.urls import urlpattern, urlresolver            # django自定义的类,可以判断当前url是否为根路径(urlpattern)或继续向下分发(urlresolver )

def check_url_exclude(url):
    """
    排除一些特定的url
    :param url: 待检验的url
    :return:
    """
    for regex in settings.auto_discover_exclude:     #将要定向排除的url(可包含正则) 按照列表的形式写入配置文件 settings.auto_discover_exclude  下
        if re.match(regex, url):
            return true
"""
示例:
auto_discover_exclude = [
    '/admin/.*',
    '/login/',
    '/logout/',
    '/index/',
]
"""
def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict):
    """
    递归的去获取url
    :param pre_namespace: namespace前缀,用于拼接name
    :param pre_url: url前缀,用于拼接url
    :param urlpatterns: 路由关系列表
    :param url_ordered_dict: 用于保存递归中获取的所有路由
    :return:
    """
    for item in urlpatterns:
        if isinstance(item, urlpattern):  # 已经是根网址,获取name及url写入url_ordered_dict
            if not item.name:  # 没有别名(name)的路由地址直接跳过
                continue
            # 拼接路由别名(包含分发下来的namespace;如 "rbac:menu_list")
            if pre_namespace:
                name = "%s:%s" % (pre_namespace, item.name)
            else:
                name = item.name
            # 拼接路由地址url(包含分发下来的上层路由;如 "/rbac/menu/list")
            url = pre_url + item.pattern.regex.pattern        # 此时拼接的路由包含起止符号,如:/^rbac/^menu/list/$
            url = url.replace("^", "").replace("$", "")           # 删除起止符:/rbac/menu/list/
            # 排除一些特定的路由url
            if check_url_exclude(url):                             # 调用check_url_exclude函数定向排除部分url
                continue
            url_ordered_dict[name] = {"name": name, "url": url}

        elif isinstance(item, urlresolver):  # 路由分发,递归操作
            if pre_namespace:                                                                              # 上次循环(上一层)分发是否包含namespace
                if item.namespace:                                                                         # 本次循环(当前层)是否包含namespace
                    namespace = "%s:%s" % (pre_namespace, item.namespace,)         # 上层、当前层都包含直接拼接两层的namespace
                else:
                    namespace = pre_namespace                                                      # 当前层分发不包含namespace,直接用上一层的
            else:
                if item.namespace:
                    namespace = item.namespace                                                     # 上一层分发不包含namespace,直接使用当前层的
                else:
                    namespace = none                                                                     # 上一层、当前层都没有,直接定义层none
            recursion_urls(namespace, pre_url + item.pattern.regex.pattern, item.url_patterns, url_ordered_dict)       # 递归继续执行
def get_all_url_dict():
    """
    获取项目所有路由
    :return:
    """
    url_ordered_dict = ordereddict()                                        # 包含本项目所有权限url的有序字典
    md = import_string(settings.root_urlconf)                    # 配置文件内的 root_urlconf 为本项目根路由urls.py 的路径(字符串),使用 import_string 用字符串加载模块
    recursion_urls(none, "/", md.urlpatterns, url_ordered_dict)    # 调用 recursion_urls 函数获取所有路由字典,根路径下没有namespace 定义为 none;没有url前缀 定义为 /
    return url_ordered_dict

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!

上一篇:

下一篇: