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/

相关推荐
龘龍龙3 分钟前
Python基础学习(四)
开发语言·python·学习
洵有兮1 小时前
python第四次作业
开发语言·python
kkoral1 小时前
单机docker部署的redis sentinel,使用python调用redis,报错
redis·python·docker·sentinel
BoBoZz191 小时前
IterativeClosestPoints icp配准矩阵
python·vtk·图形渲染·图形处理
test管家1 小时前
PyTorch动态图编程与自定义网络层实战教程
python
laocooon5238578862 小时前
python 收发信的功能。
开发语言·python
清水白石0082 小时前
《Python 责任链模式实战指南:从设计思想到工程落地》
开发语言·python·责任链模式
沛沛老爹2 小时前
Web开发者快速上手AI Agent:基于LangChain的提示词应用优化实战
人工智能·python·langchain·提示词·rag·web转型
宁大小白2 小时前
pythonstudy Day39
python·机器学习
拾贰_C2 小时前
【VSCode | python | anaconda | cmd | PowerShell】在没有进入conda环境时使用conda命令默认安装位置
vscode·python·conda