Django REST Framework结合了来自不同应用程序的路由器

时间:2015-07-17 19:24:48

标签: django django-rest-framework

我有一个跨多个应用的​​项目:

./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文件中定义的所有单独路由器都包含在一个路由器中,但我找不到有关如何执行此操作的文档。我错过了一些明显的东西吗?

6 个答案:

答案 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)

@Colton Hicks评论

假设我们在“ 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视图

相关问题