DRF可浏览API中不显示已引入的应用URL
我明白你遇到的问题了——把路由拆分到各个app的urls.py后,API能正常访问,但DRF的可浏览API根页面就是不显示这些拆分出去的路由,不过drf-spectacular却能正确识别。这其实是DRF可浏览API的一个设计特点,不是bug,咱们一步步来解决。
为什么会出现这个情况?
DRF的可浏览API根页面是由你在根urls.py里初始化的DefaultRouter生成的,这个根路由器只会展示自己直接注册的ViewSet路由。而你拆分到een app里的是另一个独立的DefaultRouter,通过include引入后,它的路由属于单独的分支,根路由器根本“不知道”这些路由的存在,自然不会在根页面展示它们。
至于drf-spectacular能识别,是因为它会遍历整个项目的urlpatterns来收集API信息,不管路由属于哪个路由器,所以不受这个限制。
解决办法
这里有两种常用方案,你可以根据自己的项目需求选择:
方案一:将子app的路由器合并到主路由器(推荐)
这种方法能让根路由器自动包含所有app的路由,可浏览API根页面也会自动展示所有链接,无需手动维护。
修改你的根urls.py:
# urls.py from django.contrib import admin from django.urls import include, path from rest_framework.routers import DefaultRouter # 导入子app的路由器 from een.urls import router as een_router import core.views router = DefaultRouter() # 注册core模块的视图集 router.register(r'core/settings', core.views.SettingsViewSet, basename='settings') router.register(r'core/organization', core.views.OrgViewSet, basename='org') # 合并een模块的路由器注册项 router.registry.extend(een_router.registry) urlpatterns = [ path('api/', include(router.urls)), # 移除原来的 path('api/een/', include('een.urls')),因为已经合并了 path('admin/', admin.site.urls), path('', include('rest_framework.urls', namespace='rest_framework')), path('api/tokenauth/', authviews.obtain_auth_token), ]
这样操作后,主路由器就包含了所有ViewSet的注册信息,访问/api/时就能看到所有路由了。
方案二:自定义API根视图(适合完全保持路由拆分的场景)
如果你不想合并路由器,希望每个app的路由完全独立,可以自定义一个根视图,手动列出所有API入口:
修改根urls.py:
from django.contrib import admin from django.urls import include, path from rest_framework.routers import DefaultRouter from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework.reverse import reverse import core.views router = DefaultRouter() router.register(r'core/settings', core.views.SettingsViewSet, basename='settings') router.register(r'core/organization', core.views.OrgViewSet, basename='org') # 自定义根视图 @api_view(['GET']) def api_root(request, format=None): return Response({ # core模块的路由 'core/settings': reverse('settings-list', request=request, format=format), 'core/organization': reverse('org-list', request=request, format=format), # een模块的路由,注意要使用app_name的命名空间 'een/cvs': reverse('een:een-cvs-list', request=request, format=format), # 后续新增路由都需要在这里手动添加 }) urlpatterns = [ path('api/', api_root), # 把自定义根视图放在最前面 path('api/', include(router.urls)), path('api/een/', include('een.urls')), path('admin/', admin.site.urls), path('', include('rest_framework.urls', namespace='rest_framework')), path('api/tokenauth/', authviews.obtain_auth_token), ]
这种方式的缺点是需要手动维护根视图里的链接,新增路由时要记得更新,但好处是能完全保持各app路由的独立性。
补充说明
如果你保留原来的include方式,其实访问/api/een/是能看到该app下的路由列表的——这是子app里的DefaultRouter生成的页面,但根页面/api/只会展示主路由器的内容。
备注:内容来源于stack exchange,提问作者normic




