9-28 6 views
最近在做权限、菜单管理平台,用于管理整个运维体系上所有模块的前端页面菜单、按钮及后端API认证权限,在平台上一个一个手动添加API接口也不现实,就想着结合框架自身的功能,自动获取所有的API接口及允许的method,拔了拔源码还是比较简单的,于是就封装成了一个类,所有独立的工程里面都放了一份通过Portal的API循环调用各独立模块儿的这个接口汇总成一个大的接口列表,基类代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Author : Eric Winn # @Email : eng.eric.winn@gmail.com # @Time : 2019/9/27 23:04 PM # @Version : 1.0 # @File : base # @Software : PyCharm import re from importlib import import_module from rest_framework.views import APIView from rest_framework.compat import URLPattern, URLResolver, get_original_route from django.utils import six from django.contrib.admindocs.views import simplify_regex from django.conf import settings class API_PATH: """ 获取本项目的API列表 """ _PATH_PARAMETER_COMPONENT_RE = re.compile(r'<(?:(?P<converter>[^>:]+):)?(?P<parameter>\w+)>') def get_apis(self): data = [] urlconf = settings.ROOT_URLCONF if not isinstance(urlconf, six.string_types): return [] urls = import_module(urlconf) patterns = urls.urlpatterns data = self.__get_api_endpoints(patterns) return data def __is_api_view(self, callback): """ 如果给定的视图回调是DRF View/viewset,则返回True """ cls = getattr(callback, 'cls', None) return (cls is not None) and issubclass(cls, APIView) def endpoint_ordering(self, endpoint): """ 返回排序字段 :param endpoint: :return: """ path, method, describe = endpoint.values() method_priority = { 'GET': 0, 'POST': 1, 'PUT': 2, 'PATCH': 3, 'DELETE': 4 }.get(method, 5) return (path, method_priority) def __get_path_from_regex(self, path_regex): """ 给定URL conf正则表达式,返回URI模板字符串 """ path = simplify_regex(path_regex) path = re.sub(self._PATH_PARAMETER_COMPONENT_RE, r'{\g<parameter>}', path) return path def __should_include_endpoint(self, path, callback): """ 如果应该包含给定的endpoint,则返回“ True” """ if not self.__is_api_view(callback): return False if callback.cls.schema is None: return False if 'schema' in callback.initkwargs: if callback.initkwargs['schema'] is None: return False if path.endswith('.{format}') or path.endswith('.{format}/'): return False return True def __get_allowed_methods(self, callback): """ 返回允许的http method列表 """ if hasattr(callback, 'actions'): actions = set(callback.actions) http_method_names = set(callback.cls.http_method_names) methods = [method.upper() for method in actions & http_method_names] else: methods = callback.cls().allowed_methods return [method for method in methods if method not in ('OPTIONS', 'HEAD')] def __get_api_endpoints(self, patterns=None, prefix=''): """ 通过检查URL conf返回所有可用API端点的列表 """ if patterns is None: patterns = patterns api_endpoints = [] for pattern in patterns: path_regex = prefix + get_original_route(pattern) if isinstance(pattern, URLPattern): path = self.__get_path_from_regex(path_regex) callback = pattern.callback if self.__should_include_endpoint(path, callback): for method in self.__get_allowed_methods(callback): endpoint = {"api": path, "describe": str(callback.initkwargs['description']).strip().split('\n')[0] if callback.initkwargs.get('description') else str(callback.__doc__).strip().split('\n')[0], "method": method} api_endpoints.append(endpoint) elif isinstance(pattern, URLResolver): nested_endpoints = self.__get_api_endpoints( patterns=pattern.url_patterns, prefix=path_regex ) api_endpoints.extend(nested_endpoints) api_endpoints = sorted(api_endpoints, key=self.endpoint_ordering) return api_endpoints |
如果想赏钱,可以用微信扫描下面的二维码,一来能刺激我写博客的欲望,二来好维护云主机的费用; 另外再次标注博客原地址 itnotebooks.com 感谢!
