Package: restful-dj
restful-dj基于 Django2/3 的 restful 自动路由框架。此包解决的问题：告别 Django 繁锁的路由配置更便捷的 restful 编码体验自动解析/校验请求参数，填充到路由处理函数安装Gitee:https://gitee.com/hyjiacan/restful-djGithub:https://github.com/hyjiacan/restful-djPyPI:https://pypi.org/project/restful-dj/pipinstallrestful-dj使用此组件提供的包（package）名称为restful_dj，所有用到的模块都在此包下引入。示例：fromrestful_djimportroutefromenumsimportRouteTypes@route('module_name','route_name',route_type=RouteTypes.TEST)deftest(req):pass装饰器@route用于标记路由处理函数。RouteTypes是自定义的路由数据。restful-dj包含以下几个部分：路由映射为了避免在客户端暴露代码路径，从设计上使用了映射的方式来处理请求。中间件在处理请求/响应过程中，可以对request/response以及其参数进行处理。全局类型在路由装饰器的参数中包含的全局类型，如RouteTypes路由收集与持久化为了提高线上性能的工具。restful-dj的使用流程如下：注册请求路径前缀注册路由映射注册中间件编写路由处理函数发布注册请求路径前缀在项目的根urls.py文件中，使用以下配置fromdjango.urlsimportpathimportrestful_djurlpatterns=[path('any/prefix',restful_dj.dispatch)]其中，any/prefix是用户自定义的url前缀，可以使用空串''，表示没有特定前缀。restful_dj.dispatch中路由的分发入口。注：可以通过部署地址any/prefix访问接口列表 (仅在开发模式时可用)，
如：http://localhost:8000/any/prefix。注册路由映射为了避免在客户端暴露代码路径(同时避免意外访问未授权的代码)，从设计上使用了映射的方式来处理请求。注册方式如下：importrestful_djrestful_dj.map_routes({'path.prefix':'path.to',})path.prefix为请求的路径path.to为请求路径时，应将其定向到的 python 包/模块。所有的路由目录(顶层，不包含已经映射过目录的子目录)均需要被映射，未在映射表中的路径请求，不会被处理。restful-dj会自动查找 包/模块path.to下的所有路由。路径应为基于项目根目录的相对路径。注册中间件中间件用于在处理请求/响应过程中，对request/response以及其参数进行处理。注册方式如下：importrestful_djfrompath.toimportFooMiddlewarefrompath.toimportBarMiddlewarerestful_dj.register_middlewares(FooMiddleware,BarMiddleware,)当注册了多个中间件时，它们会按被注册的顺序执行。需要注意： 每一个中间件类型在程序运行期间共享一个实例。如何开发中间件？参见中间件类结构编写路由处理函数路由文件位置没有要求，只要配置好就可以了。importrestful_djrestful_dj.map_routes({'test':'test.api'})此配置表示，所有请求中以test开头的地址，都会交由test.api下的模块进行处理。使用装饰器route标记路由处理函数。test/api/demo.pyfromdjango.httpimportHttpRequestfromrestful_dj.decoratorimportroute@route(module='module-name',name='name')defget(request,param1,param2=None,param3:int=5):# request 会是 HttpRequestreturn{'param1':param1,'param2':param2,'param3':param3,}@route(module='module-name',name='name')defget_param(param1,req:HttpRequest,from_=None,param3=5):# req 会是 HttpRequestreturn{'param1':param1,'from':from_,'param3':param3,}@route(module='module-name',name='name')defget_param(request:str,param1,from_=None,param3=5):# request 会是请求参数，参数列表中没有 HttpRequestreturn{'request':request,'param1':param1,'from':from_,'param3':param3,}@route(module='module-name',name='name')defget_param(request,param1,from_=None,param3=5,**kwargs):# 未在函数的参数列表中声明的请求参数，会出现在 kwargs 中return{'param1':param1,'from':from_,'param3':param3,'variable_args':kwargs}一些需要注意的地方：当代码中需要使用关键字作为名称时，请在名称后添加_，此时前端请求时，_符号可省略，
如:from_在请求时可写作from=test（from_=test亦可）。对于语言间的命令差异，可以自动兼容下划线命名法与驼峰命名法，如：请求参数中的pageIndex，在处理函数中可以写作page_index或_page_index_，
也就是说，在前后添加_符号都不会影响参数的解析。路由处理函数可以添加一个可变参数(如：**kwargs**)，用于接收未在参数列表中列出的请求项。
当然，kwargs和普通函数一样，可以是任何其它名称。request参数(与参数位置无关)，可能被解析成三种结果(1和2均会将其作为HttpRequest参数处理)：参数名称为request，并且未指定参数类型(或指定类型为HttpRequest)参数类型为HttpRequest，参数名称可以是任何合法的标识符参数名称为request，声明了不是HttpRequest的类型，此时会被解析成一般的请求参数前端调用:// 请求 get 函数ajax.get('test.demo?param1=1&param2=2&param3=3')// 请求 get_param 函数ajax.get('test.demo/param?param1=1&param2=2&param3=3')路由可以返回任何类型的数据。路由会自动根据函数定义来判断传入参数的类型是否合法。比如前面示例中的param3: int =5，会根据声明类型int去判断传入类型如果传入了字符串类型的数值，路由会自动转换成数值类型另外，如果设置了None以外的默认值，那么路由会根据默认值的类型自动去判断，
此时可以省略参数类型，如:param3: int =5省略为param3=5装饰器装饰器route用于声明某个函数可以被路由使用。通过添加此装饰器以限制非路由函数被非法访问。声明为：defroute(module=None,name=None,**kwargs):passmodule此路由所属的业务/功能模块名称name此路由的名称**kwargs额外参数这些参数都会被传递给中间件的各个函数的参数meta。详细见RouteMeta同时，此装饰器会自动尝试将request.body，request.GET和request.POST处理成 JSON 格式(仅在content-type=application/json时)，
并且分别添加到request.B，request.G和request.P属性上。注意：一般情况下，使用路由处理函数就能完全操作请求参数，应该尽量减少使用B/P/G，以避免代码的不明确性。发布发布指将 Django 项目发布到服务器上运行(线上环境)。一般来说，发布时只需要调用生成路由映射文件的接口就可以了，
路由收集在其中会自动调用。路由收集路由收集器用于收集项目中的所有路由，通过以下方式调用:importrestful_djroutes=restful_dj.collect()routes是一个可以直接迭代的路由数组其每一个路由项的结构如下:modulenamekwargsidpkg # 路由所在包名称file # 路由所在文件的完整路径handler # 路由请求的处理函数method # 路由的请求方法path # 路由的请求路径生成路由映射文件since 1.0.3restful-dj导出了一个工具函数persist，用于将路由收集起来，并持久化，其用法如下：importosfromdjango.confimportsettingsimportrestful_djrestful_map=os.path.join(settings.BASE_DIR,'path/to/restful_map.py')# restful_map 参数是可选的，当不传时，调用会返回生成的代码内容# encoding 参数是可选的，默认值为 utf-8。restful_dj.persist(restful_map,encoding='utf-8')此处还需要调用路由的映射注册，以及全局类型注册等。
因此，最佳方法就是，将这些注册写一个单独的 python 文件，在启动和发布时均调用即可。最终生成的路由代码会写入文件restful_map.py，此文件会暴露一个数据项routes，其中是所有的路由映射。
一般来说，应该在系统启动时 (在主应用的urls.py文件中) 调用此函数:importrestful_djfrompath.toimportrestful_maprestful_dj.register_routes(restful_map.routes)综上，发布以及线上运行流程为：发布时调用restful_dj.persist生成路由映射文件程序启动时，判断settings.DEBUG=False，执行from path.to import restful_map并调用restful_dj.register_routes(restful_map.routes)注册路由。高级用法分发前的处理有的时候，需要在分发前对请求参数进行处理。此时可以使用restful.set_before_dispatch_handler来进行一些预处理。函数签名:defset_before_dispatch_handler(handler):pass用法:importrestful_djdefbefore_dispatch_handler(request,entry,name):# 可以在此处修改 request 的数据# 也可以重新定义 entry 和 namereturnentry,namerestful_dj.set_before_dispatch_handler(before_dispatch_handler)注册全局类型当在路由装饰器参数中使用了自定义的值类型时（比如枚举或类），应该当将其注册到restful-dj，否则无法正确收集到路由。例：test.pyfromrestful_djimportroutefromenumsimportRouteTypes@route('module_name','route_name',route_type=RouteTypes.TEST)deftest(req):passenums.pyfromenumimportEnumclassRouteTypes(Enum):TEST=1注册自定义日志记录器fromrestful_djimportset_loggerdefmy_logger(level:str,message:str,e:Exception):passset_logger(my_logger)其中，level表示日志级别，会有以下值：debuginfosuccesswarningerror中间件类结构path.to.MiddlewareClassfromdjango.httpimportHttpRequestfromrestful_djimportRouteMetaclassMiddlewareClass:"""路由中间件"""defprocess_request(self,request:HttpRequest,meta:RouteMeta,**kwargs):"""对 request 对象进行预处理。一般用于请求的数据的解码，此时路由组件尚水进行请求数据的解析(B,P,G 尚不可用):param request::param meta::return: 返回 HttpResponse 以终止请求，返回 False 以停止执行后续的中间件(表示访问未授权)，返回 None 或不返回任何值继续执行后续中间件"""passdefprocess_invoke(self,request:HttpRequest,meta:RouteMeta,**kwargs):"""在路由函数调用前，对其参数等进行处理，此时路由组件已经完成了请求数据的解析(B,P,G 已可用)此时可以对解析后的参数进行变更:param request::param meta::return: 返回 HttpResponse 以终止请求，返回 False 以停止执行后续的中间件(表示访问未授权)，返回 None 或不返回任何值继续执行后续中间件"""passdefprocess_return(self,request:HttpRequest,meta:RouteMeta,**kwargs):"""在路由函数调用后，对其返回值进行处理:param request::param meta::param kwargs: 始终会有一个 'data' 的项，表示返回的原始数据:return: 返回 HttpResponse 以终止执行，否则返回新的 return value"""assert'data'inkwargsreturnkwargs['data']defprocess_response(self,request:HttpRequest,meta:RouteMeta,**kwargs):"""对 response 数据进行预处理。一般用于响应的数据的编码:rtype: HttpResponse:param meta::param request::param kwargs: 始终会有一个 'response' 的项，表示返回的 HttpResponse:return: 无论何种情况，应该始终返回一个  HttpResponse"""assert'response'inkwargsreturnkwargs['response']RouteMeta路由元数据，中间件中勾子函数的参数meta结构。fromtypesimportFunctionTypefromtypingimportOrderedDictclassRouteMeta:@propertydefhandler(self)->FunctionType:"""路由处理函数对象:return:"""returnself._handler@propertydeffunc_args(self)->OrderedDict:"""路由处理函数参数列表:return:"""returnself._func_args@propertydefid(self)->str:"""路由ID，此ID由路由相关信息组合而成:return:"""returnself._id@propertydefmodule(self)->str:"""装饰器上指定的 module 值:return:"""returnself._module@propertydefname(self)->str:"""装饰器上指定的 name 值:return:"""returnself._name@propertydefkwargs(self)->dict:"""装饰器上指定的其它参数:return::rtype: Dict"""returnself._kwargs另外，meta 还提供了has和get两个方法，其描述如下：has(arg_name)判断是否指定了额外参数get(arg_name, default_value=None)若存在指定名称的额外参数，则返回值，否则返回指定的默认值额外参数: 除name和module外的参数待办事项添加严格模式支持。在严格模式下，不允许传入未声明的参数。参数类型支持上传文件常见问题403 Forbidden. CSRF verification failed. Request aborted.移除或注释掉settings.py文件中的中间件'django.middleware.csrf.CsrfViewMiddleware'restful 请求时，前端页面并没有 Django 生成的 form 以及对应的 csrf 校验字段，此配置实际上对 restful 是没有意义的。更新记录2.0.0新的restful-dj启动方式修复 api 列表页面可能导致的异常问题移除DotDict支持移除@route的保留参数1.0.3优化 线上路由加载方式，提升启动和响应速度优化 路由处理函数被用户直接调用的支持优化 将兼容性调整为 Python 3.5