权限组件(12):自动发现项目中有别名的URL

Posted lshedward

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了权限组件(12):自动发现项目中有别名的URL相关的知识,希望对你有一定的参考价值。

自动发现项目中所有有别名的URL,效果如下:

customer_list {name: customer_list, url: /customer/list/}
customer_add {name: customer_add, url: /customer/add/}
customer_edit {name: customer_edit, url: /customer/edit/(?P<cid>\d+)/}
customer_del {name: customer_del, url: /customer/del/(?P<cid>\d+)/}
customer_import {name: customer_import, url: /customer/import/}
customer_tpl {name: customer_tpl, url: /customer/tpl/}
payment_list {name: payment_list, url: /payment/list/}
payment_add {name: payment_add, url: /payment/add/}
payment_edit {name: payment_edit, url: /payment/edit/(?P<pid>\d+)/}
payment_del {name: payment_del, url: /payment/del/(?P<pid>\d+)/}
rbac:role_list {name: rbac:role_list, url: /rbac/role/list/}
rbac:role_add {name: rbac:role_add, url: /rbac/role/add/}
rbac:role_edit {name: rbac:role_edit, url: /rbac/role/edit/(?P<pk>\d+)/}
rbac:role_del {name: rbac:role_del, url: /rbac/role/del/(?P<pk>\d+)/}
rbac:user_list {name: rbac:user_list, url: /rbac/user/list/}
rbac:user_add {name: rbac:user_add, url: /rbac/user/add/}
rbac:user_edit {name: rbac:user_edit, url: /rbac/user/edit/(?P<pk>\d+)/}
rbac:user_del {name: rbac:user_del, url: /rbac/user/del/(?P<pk>\d+)/}
rbac:user_reset_pwd {name: rbac:user_reset_pwd, url: /rbac/user/reset/password/(?P<pk>\d+)/}
rbac:menu_list {name: rbac:menu_list, url: /rbac/menu/list/}
rbac:menu_add {name: rbac:menu_add, url: /rbac/menu/add/}
rbac:menu_edit {name: rbac:menu_edit, url: /rbac/menu/edit/(?P<pk>\d+)}
rbac:menu_del {name: rbac:menu_del, url: /rbac/menu/del/(?P<pk>\d+)}
rbac:second_menu_add {name: rbac:second_menu_add, url: /rbac/second/menu/add/(?P<menu_id>\d+)/}
rbac:second_menu_edit {name: rbac:second_menu_edit, url: /rbac/second/menu/edit/(?P<pk>\d+)/}
rbac:second_menu_del {name: rbac:second_menu_del, url: /rbac/second/menu/del/(?P<pk>\d+)/}
rbac:permission_add {name: rbac:permission_add, url: /rbac/permission/add/(?P<second_menu_id>\d+)/}
rbac:permission_edit {name: rbac:permission_edit, url: /rbac/permission/edit/(?P<pk>\d+)/}
rbac:permission_del {name: rbac:permission_del, url: /rbac/permission/del/(?P<pk>\d+)/}
rbac:multi_permissions {name: rbac:multi_permissions, url: /rbac/multi/permissions/}

一、配置路由

rbac/urls.py

from django.urls import re_path

...
from rbac.views import menu
...
urlpatterns = [
    ...
    # 批量操作权限
    re_path(r^multi/permissions/$, menu.multi_permissions, name=multi_permissions)  # 自动发现项目中的所有URL
    ...
]

二、自动发现URL功能实现

排除不用发现的URL

settings.py

...
AUTO_DISCOVER_EXCLUDE = [
    /admin/,
    /login/,
]
...

 

rbac/service/router.py

import re

from collections import OrderedDict

from django.conf import settings
from django.utils.module_loading import import_string  # 根据字符串的形式,帮我们去导入模块
from django.urls import URLPattern, URLResolver  # 路由分发:URLResolver。非路由分发:URLPattern


def check_url_exclude(url):
    """
    排除一些特定的url
    :param url:
    :return:
    """
    for regex in settings.AUTO_DISCOVER_EXCLUDE:
        if re.match(regex, url):
            return True


def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict):
    """
    :param pre_namespace: namespace前缀(rbac:xxx),以后用于拼接name
    :param per_url: url的前缀(rbac/xxx),以后用于拼接url
    :param urlpatterns: 路由关系列表
    :param url_ordered_dict: 用于保存递归中获取的所有路由
    :return:
    """

    # 路由分发:URLResolver。非路由分发:URLPattern
    for item in urlpatterns:
        if isinstance(item, URLPattern):  # 非路由分发,将路由添加到url_ordered_dict
            if not item.name:  # url中反向命名的name,没有的话不做处理,直接跳过。
                continue
            if pre_namespace:  # 如果有命名空间就进行拼接。示例:rbac:role_list
                name = f{pre_namespace}:{item.name}
            else:
                name = item.name  # 示例:role_list

            # 判断url有没有前缀,如果有前缀的话我们要给它拼接上,一般url都是有前缀的,因为从根级路由开始我们就加了个/
            url = pre_url + item.pattern.regex.pattern  # pattern.regex.pattern是拿到当前url django 1.X里是 url._regex
            # 拼接完长这样:/^rbac/^user/edit/(?P<pk>d_+)/$
            url = url.replace(^, ‘‘).replace($, ‘‘)  # 把起始符和终止符替换成空的,最后得到:/rbac/user/edit/(?P<pk>d_+)/

            if check_url_exclude(url):  # 判断是否admin、login等我们不需要的url,是的话直接跳过
                continue

            url_ordered_dict[name] = {name: name, url: url}
            # ‘rbac:menu_list‘:{name:‘rbac:menu_list‘,url:‘xxxxx/yyyy/menu/list‘}

        elif isinstance(item, URLResolver):  # 路由分发,进行递归操作
            if pre_namespace:
                """
                # 有前缀  示例:admin 。admin.site.urls的urls的返回值是:
                @property
                def urls(self):
                    return self.get_urls(), ‘admin‘, self.name。 返回值的第二个是命名空间
                """
                if item.namespace:  # 如果有自己的namespace比如说user_list,和前面的pre_namespace进行拼接,结果是rbac:user_list
                    namespace = f"{pre_namespace}:{item.namespace}"
                else:
                    """
                    自己没有namespace,但是父级有,那么namespace就应该是父级的,所以那就直接应该是rbac。
                    示例:re_path(r‘^role/list/$‘, include(‘xxx.urls‘))。rbac里的一条路由又进行路由分发,但是自己没有命名空间
                    """
                    namespace = item.namespace  # 写成namespace = pre_namespace也可以
            else:
                if item.namespace:  # 父级没有namespace,自己有。示例:re_path(r‘^rbac/‘, include((‘rbac.urls‘, ‘rbac‘)), )
                    namespace = item.namespace
                else:  # 父级没有namespace,自己也没有
                    namespace = None

            recursion_urls(namespace, pre_url + item.pattern.regex.pattern, item.url_patterns, url_ordered_dict)

            """
            pre_url(上一级的url) + item.pattern.regex.pattern(当前路由分发的前缀),item.url_patterns(当前路由分发的urlpatterns)
            拿re_path(r‘^rbac/‘, include((‘rbac.urls‘, ‘rbac‘)))举例:
            namespace = rbac,  pre_url=/,  item.pattern.regex.pattern=^rbac/,item.url_patterns = rbac.urls下的所有url
            在django1.x里item.pattern.regex.pattern要换成item.regex.pattern
            """


def get_all_url_dict():
    """
    获取项目中所有的URL(必须有name别名)
    :return:
    """

    url_ordered_dict = OrderedDict()

    all_url = import_string(settings.ROOT_URLCONF)  # from permission_learn import urls

    recursion_urls(None, /, all_url.urlpatterns, url_ordered_dict)  # 递归的去获取所有的路由。根目录没有namespace,根路由用/

    # 得到类似这样的结果:
    """
    {
        ‘rbac:menu_list‘:{name:‘rbac:menu_list‘,url:‘xxxxx/yyyy/menu/list‘}
    }
    """

    return url_ordered_dict

  

 

三、在视图函数引用

rbac/views/menu.py

...
from rbac.service.router import get_all_url_dict
...

...
def multi_permissions(request):
    """
    批量操作权限
    :param request:
    :return:
    """

    # 获取项目中所有的url

    all_url_dict = get_all_url_dict()
    for k, v in all_url_dict.items():
        print(k, v)

    return HttpResponse(ok it)
...

 

以后我们需要在页面展示这些URL,并对其进行增删改和权限操作

 

 

以上是关于权限组件(12):自动发现项目中有别名的URL的主要内容,如果未能解决你的问题,请参考以下文章

C# URL传值中有一个#符号传不过去

Vue cli 3项目别名src到@或~/不起作用

在视图上生成 URL 时,Laravel 命名路由方法不会生成主机服务器的 (apache) 别名

在新项目下使用rbc权限

权限

修复项目发布节点的扭曲URL别名