zoukankan      html  css  js  c++  java
  • 权限组件(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 + str(item.pattern)
                # 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('$', '').replace('/', '/')
                # 把起始符和终止符替换成空的,最后得到:/rbac/user/edit/(?P<pk>d_+)/
                # django2.0中的path会多一个反斜杠,例子:'/rbac/permission/del/(?P<pk>d+)/'
                # 为了兼容django2.0中的path,要把/换成/,最后成为:/rbac/permission/del/(?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:user_list里的url
                        namespace = f"{pre_namespace}:{item.namespace}"
                    else:
                        """
                        自己没有namespace,但是父级有,那么namespace就是None
                        示例:re_path(r'^role/list/$', include('xxx.urls'))。rbac里的一条路由又进行路由分发,但是自己没有命名空间
                        """
                        namespace = item.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 + str(item.pattern), item.url_patterns, url_ordered_dict)
                # 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
           如果rbac里还有路由分发的话,比如说rbac2,那么pre_url + str(item.pattern) 就是 rbac/rbac2,传到非路由分发的方法那就会继续拼接成如:rbac/rbac2/add/
    """ 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,并对其进行增删改和权限操作

  • 相关阅读:
    BZOJ1001 BJOI2006 狼抓兔子
    NOI2015 程序自动分析
    高斯消元法
    [POJ] 3666 Making the Grade
    [CODEVS] 2185 最长公共上升子序列
    [模板] LIS
    [CF] 219D Choosing Capital for Treeland
    [POJ] 2823 Sliding Window
    [BZOJ] 1072 [SCOI2007]排列perm
    [POJ] 1094 Sorting It All Out
  • 原文地址:https://www.cnblogs.com/lshedward/p/10518270.html
Copyright © 2011-2022 走看看