我有一个跨多个应用的项目:
./project/app1
./project/app2
./project/...
每个应用都有一个Django REST Framework路由器,可以整合该应用提供的API部分:
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from .views import ThingViewSet
router = DefaultRouter()
router.register(r'things', ThingViewSet, base_name='thing')
urlpatterns = [
url(r'^', include(router.urls)),
]
由于应用是独立的,我的顶级网址文件(./project/urls.py
)包含来自不同应用的每个网址文件:
url(r'^api/app1/', include('app1.urls', namespace='a1')),
url(r'^api/app2/', include('app2.urls', namespace='a2')),
这意味着Django REST Framework为每个应用程序显示一个单独的API根目录。但是,我想要的是一个统一的API结构,因此,如果我导航到http://example.com/api/
,我会看到该层次结构中所有可用URL的完整列表。
我认为有一种方法可以将每个应用程序的各个urls.py
文件中定义的所有单独路由器都包含在一个路由器中,但我找不到有关如何执行此操作的文档。我错过了一些明显的东西吗?
答案 0 :(得分:36)
另一种解决方案是使用SimpleRouter
为各个应用定义路由器。然后,使用自定义的DefaultRouter
来包含应用程序特定的路由。这样,所有特定于应用程序的URL定义都将保留在相应的应用程序中。
假设您有两个名为“app1”和“app2”的应用程序,每个应用程序都有一个名为“api”的目录,并且在此目录中有一个名为“urls”的文件,其中包含您的所有路径定义。
├── project/
│ ├── api_urls.py
│ ├── app1
│ │ ├── api
│ │ │ ├── urls.py
│ ├── app2
│ │ ├── api
│ │ │ ├── urls.py
│ ├── patches
│ │ ├── routers.py
使用patches/router.py
定义一个名为DefaultRouter
的类,该类继承自rest_framework.routers.DefaultRouter
。
from rest_framework import routers
class DefaultRouter(routers.DefaultRouter):
"""
Extends `DefaultRouter` class to add a method for extending url routes from another router.
"""
def extend(self, router):
"""
Extend the routes with url routes of the passed in router.
Args:
router: SimpleRouter instance containing route definitions.
"""
self.registry.extend(router.registry)
使用
等路线定义填写您的API"""
URL definitions for the api.
"""
from patches import routers
from app1.api.urls import router as app1_router
from app2.api.urls import router as app2_router
router = routers.DefaultRouter()
router.extend(app1_router)
router.extend(app2_router)
答案 1 :(得分:14)
这将获取基本API URL上列出的所有ViewSet路由。
它将路由定义为相应包含的app.urls中的列表,以便它们可以在其他地方注册。
在基础urls.py中包含它们之后,嵌套的列表列表将被构建并循环以在API中注册同一级别的所有路由
# foo.urls
routeList = (
(r'foos', FooViewSet),
)
# barBaz.urls
routeList = (
(r'bars', BarViewSet),
(r'bazs', BazViewSet),
)
# urls
from rest_framework import routers
from foo import urls as fooUrls
from barBaz import urls as barBazUrls
routeLists = [
fooUrls.routeList,
barBazUrls.routeList,
]
router = routers.DefaultRouter()
for routeList in routeLists:
for route in routeList:
router.register(route[0], route[1])
结果:
{
"foo": "http://localhost:8000/foos/",
"bar": "http://localhost:8000/bars/",
"baz": "http://localhost:8000/bazs/",
}
每个文件的重复次数也较少,可以说更容易阅读。
此外,它仍然完全解耦。
如果在其他地方使用了包含的应用程序,可以在内部使用相同的方法来注册它自己的路由,而不必包含在任何地方。
放弃外部循环
routeList = (
(r'bars', BarViewSet),
(r'bazs', BazViewSet),
)
router = routers.DefaultRouter()
for route in routeList:
router.register(route[0], route[1])
答案 2 :(得分:6)
我最终在urls_api_v1.py中创建了一个包含我想要的所有路由的URL文件:
router = DefaultRouter()
router.register(r'app1/foos', FooViewSet, base_name='foo')
router.register(r'app2/bars', BarViewSet, base_name='bar')
router.register(r'app2/bazs', BazViewSet, base_name='baz')
作为一个副作用,这让我可以摆脱每个应用程序中你通常想要的所有个人urls.py文件,但在这种情况下,整个应用程序集合需要统一的URL结构,因此删除更多明智的。
然后我从urls.py
引用它:
import api_v1
urlpatterns = patterns('',
...,
url(r'^api/v1/', include(api_v1, namespace='api-v1')),
)
现在,如果我想更改v2的路由,我也可以包含一个v2 URL文件,并最终弃用v1文件。
答案 3 :(得分:3)
假设我们在“ apps文件夹”中有2个应用程序(权限,用户)。然后我们可以做这样的事情:
from apps.users.api.urls import router as users_router
from apps.permissions.api.urls import router as permissions_router
router = DefaultRouter()
router.registry.extend(users_router.registry)
router.registry.extend(permissions_router.registry)
答案 4 :(得分:3)
您可以使用router.registry.extend(app_router.registry)
,例如:
from django.urls import path, include
from rest_framework import routers
from app1.rest import router as app1_router
from app2.rest import router as app2_router
router = routers.DefaultRouter()
router.registry.extend(app1_router.registry)
router.registry.extend(app2_router.registry)
urlpatterns = [
path('', include(router.urls)),
]
答案 5 :(得分:0)
如果您正在实现SimpleRouter,您只需将其url与urlpatterns列表连接
router = SimpleRouter()
router.register(r'import-project', ImportProject, base_name='di-integ')
在主urls.py文件
上from di_apiary_integration.urls import router as di_integration_routers
要注册URL,您可以这样做:
url(r'^di-integration/', include(di_integration_routers.urls)),
或
urlpatterns += di_integ_router.urls
两者都有效!
重要
ImportProject需要是ModelViewSet或ViewSet,如果您将其创建为简单的APIView,则需要使用as_view()将其注册为普通的CBV视图