django drf 自动注册路由

场景

省事,不用写urls.py文件相关的代码。

代码

1.全局的config/discovery.py,我放在根目录下的config目录里,位置随意:

python 复制代码
import pkgutil
import sys
import typing as t


def import_string(import_name: str, silent: bool = False) -> t.Any:
   """Imports an object based on a string.  This is useful if you want to
   use import paths as endpoints or something similar.  An import path can
   be specified either in dotted notation (``xml.sax.saxutils.escape``)
   or with a colon as object delimiter (``xml.sax.saxutils:escape``).

   If `silent` is True the return value will be `None` if the import fails.

   :param import_name: the dotted name for the object to import.
   :param silent: if set to `True` import errors are ignored and
                  `None` is returned instead.
   :return: imported object
   """
   import_name = import_name.replace(":", ".")
   try:
       try:
           __import__(import_name)
       except ImportError:
           if "." not in import_name:
               raise
       else:
           return sys.modules[import_name]

       module_name, obj_name = import_name.rsplit(".", 1)
       module = __import__(module_name, globals(), locals(), [obj_name])
       try:
           return getattr(module, obj_name)
       except AttributeError as e:
           raise ImportError(e) from None

   except ImportError as e:  # noqa
       pass

   return None


def find_modules(
   import_path: str, include_packages: bool = False, recursive: bool = False
) -> t.Iterator[str]:
   """Finds all the modules below a package.  This can be useful to
   automatically import all views / controllers so that their metaclasses /
   function decorators have a chance to register themselves on the
   application.

   Packages are not returned unless `include_packages` is `True`.  This can
   also recursively list modules but in that case it will import all the
   packages to get the correct load path of that module.

   :param import_path: the dotted name for the package to find child modules.
   :param include_packages: set to `True` if packages should be returned, too.
   :param recursive: set to `True` if recursion should happen.
   :return: generator
   """
   module = import_string(import_path)
   path = getattr(module, "__path__", None)
   if path is None:
       raise ValueError(f"{import_path!r} is not a package")
   basename = f"{module.__name__}."
   for _importer, modname, ispkg in pkgutil.iter_modules(path):
       modname = basename + modname
       if ispkg:
           if include_packages:
               yield modname
           if recursive:
               yield from find_modules(modname, include_packages, True)
       else:
           yield modname


def auto_register():
   base_path = "sk_scan"
   for x in find_modules(base_path, recursive=True):
       if "views" in x:
           try:
               import_string(x)
           except Exception as e:
               pass


def discovery():
   auto_register()

2.全局的config/api_router.py,我放在根目录下的config目录里,位置随意:

python 复制代码
from django.conf import settings
from rest_framework.routers import DefaultRouter, SimpleRouter

from config.discovery import discovery
from sk_scan.users.api.views import UserViewSet

if settings.DEBUG:
   router = DefaultRouter()
else:
   router = SimpleRouter()

router.register("users", UserViewSet)

discovery()

app_name = "api"
urlpatterns = router.urls

3.全局urls.py文件:

python 复制代码
urlpatterns += [
   # API base url
   path("api/", include("config.api_router")),

]

4.自动注册入口,作为工具类,我放在common/drf/mixins.py文件里:

python 复制代码
class AutoRegisterMixin(object):
   basename = ""
   path = ""

   @classmethod
   def register(cls):
       from config.api_router import router
       cls.path = cls.path.lstrip("/")
       print("ViewSet: %s register, basename: %s" % (cls, cls.basename))
       router.register(cls.path, viewset=cls, basename=cls.basename)

5.视图中使用:

python 复制代码
from rest_framework.viewsets import ModelViewSet

from common.drf.mixins import AutoRegisterMixin



class TestViewSet(
   AutoRegisterMixin,  # 继承自动注册类
   ModelViewSet,
):
   path = "scan/record"  # url中的uri部分
   name = "scan/record"  # 名称
   queryset = models.TestModel.objects.all()
   serializer_class = serializers.TestSerializer


TestViewSet.register()  # 调用自动注册

6.最终,生成的接口有以下接口:

http://127.0.0.1:8000/api/scan/record/ 支持GET/POST

http://127.0.0.1:8000/api/scan/record/\<id>/ 支持GET/PUT/DELETE/

相关推荐
Salt_072832 分钟前
DAY 19 数组的常见操作和形状
人工智能·python·机器学习
a***131441 分钟前
vscode配置django环境并创建django项目(全图文操作)
vscode·django·sqlite
无心水1 小时前
【Python实战进阶】2、Jupyter Notebook终极指南:为什么说不会Jupyter就等于不会Python?
python·jupyter·信息可视化·binder·google colab·python实战进阶·python工程化实战进阶
上班日常摸鱼2 小时前
Shell脚本基础教程:变量、条件判断、循环、函数实战(附案例)
python
无心水2 小时前
【Python实战进阶】5、Python字符串终极指南:从基础到高性能处理的完整秘籍
开发语言·网络·python·字符串·unicode·python实战进阶·python工业化实战进阶
2301_807583232 小时前
了解python,并编写第一个程序,常见的bug
linux·python
小白学大数据2 小时前
构建混合爬虫:何时使用Requests,何时切换至Selenium处理请求头?
爬虫·python·selenium·测试工具
2401_827560203 小时前
【Python脚本系列】PyAudio+librosa+dtw库录制、识别音频并实现点击(四)
python·语音识别
BBB努力学习程序设计3 小时前
Python自动化脚本:告别重复劳动
python·pycharm
BBB努力学习程序设计3 小时前
Python函数式编程:优雅的代码艺术
python·pycharm