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/

相关推荐
weixin_4684668524 分钟前
遗传算法求解TSP旅行商问题python代码实战
python·算法·算法优化·遗传算法·旅行商问题·智能优化·np问题
Nina_7171 小时前
pytorch核心组件以及流程
人工智能·pytorch·python
Highcharts.js1 小时前
在Python中配置高度交互的数据可视化:Highcharts完全指南
开发语言·python·信息可视化·highcharts
Ace_31750887761 小时前
京东关键字搜索接口逆向:从动态签名破解到分布式请求调度
分布式·python
yachuan_qiao2 小时前
专业的建筑设备监控管理系统选哪家
大数据·运维·python
l1t2 小时前
DeepSeek辅助编写转换DuckDB json格式执行计划到PostgreSQL格式的Python程序
数据库·python·postgresql·json·执行计划
q***82912 小时前
【玩转全栈】----Django模板语法、请求与响应
数据库·python·django
李昊哲小课3 小时前
cuda12 cudnn9 tensorflow 显卡加速
人工智能·python·深度学习·机器学习·tensorflow
FreeCode3 小时前
LangChain1.0智能体开发:检索增强生成(RAG)
python·langchain·agent
xixixi777773 小时前
攻击链重构的具体实现思路和分析报告
开发语言·python·安全·工具·攻击链