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/

相关推荐
零意@8 分钟前
ubuntu切换不同版本的python
windows·python·ubuntu
思忖小下19 分钟前
Python基础学习_01
python
q567315231 小时前
在 Bash 中获取 Python 模块变量列
开发语言·python·bash
是萝卜干呀1 小时前
Backend - Python 爬取网页数据并保存在Excel文件中
python·excel·table·xlwt·爬取网页数据
代码欢乐豆1 小时前
数据采集之selenium模拟登录
python·selenium·测试工具
狂奔solar1 小时前
yelp数据集上识别潜在的热门商家
开发语言·python
Tassel_YUE1 小时前
网络自动化04:python实现ACL匹配信息(主机与主机信息)
网络·python·自动化
聪明的墨菲特i2 小时前
Python爬虫学习
爬虫·python·学习
努力的家伙是不讨厌的3 小时前
解析json导出csv或者直接入库
开发语言·python·json
云空3 小时前
《Python 与 SQLite:强大的数据库组合》
数据库·python·sqlite