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/

相关推荐
Envyᥫᩣ13 分钟前
Python中的机器学习:从入门到实战
python·前端框架
西贝爱学习17 分钟前
py 元组,列表,函数的学习和使用
python
weijie.zwj35 分钟前
LLM基础概念:Prompt
人工智能·python·langchain
high_tea41 分钟前
pytest - 多线程提速
python·pytest
Stringzhua1 小时前
bilibili实现批量发送弹幕功能
python
懒大王爱吃狼1 小时前
Python教程: 类命名空间
开发语言·python·python基础·pip·python教程·python编程·python学习
Eric.Lee20212 小时前
数据集-目标检测系列-鲨鱼检测数据集 shark >> DataBall
python·深度学习·算法·目标检测·数据集·鲨鱼检测
skywalk81632 小时前
Python使用最广泛的数据验证库Pydantic
python
豌豆花下猫2 小时前
Python 潮流周刊#71:PyPI 应该摆脱掉它的赞助依赖(摘要)
后端·python·ai
Tech Synapse2 小时前
Vscode 远程切换Python虚拟环境
ide·vscode·python