12

使用 django-rest-framework 我正在使用DefaultRouter

我想为几个应用程序提供 API,所以我的问题是我可以以 django 方式执行此操作,并将我的路由器注册放在每个应用程序 URLconf 中,并让它们显示为一个聚合 api 或理想情况下以命名空间的方式显示。

换句话说,如果app1包含modelAmodelB,而app2包含modelC

  1. 我可以声明出现在mysite/app1/apiand的 2 个路由器mysite/app2/api,或者
  2. 我可以有一个 apimysite/api列出所有三个模型,然后在他们自己的应用程序中注册各个模型吗urls.py

就像是

router = DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(include('app1.apis')
router.register(include('app2.apis')

或者,是否有一种简单的方法可以使我的路由器变量在每个应用程序的 URLconf 中可用,以便他们可以调用router.register?我不确定是否

urlpatterns = patterns('',
url(r'^snippets/', include('snippets.urls', namespace="snippets"))
...
url(r'^api/', include(router.urls)),

实际上导致代码在app1/urls.py此时执行,以便它可以router.register以某种方式调用,因此最终的 url 调用包括所有应用程序注册以及项目注册。

更新

使用 Nicolas Cortot 的变体,option 2我可以使用我的特定资源,但它未在atAPI中列为可用资源root APImyserver\api\

我假设以某种方式DefaultRouter创建它自己的页面定义并向其中router.register添加条目。我当前的设置(我认为 Nicholas 的选项 1 也是如此)创建了两个单独的路由器,并且只有一个可以显示为服务器根目录,下面的设置myserver\api\列出users但不是片段。

这是我当前的设置:

项目 urls.py:

router = DefaultRouter()
router.register(r'users', views.UserViewSet)

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^api/', include(router.urls)),
    url(r'^api/', include('snippets.apiurls')),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
)

项目/片段/apiurls.py:

router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)

urlpatterns = patterns('',
    url(r'^', include(router.urls)),
)

如果我将项目中条目的顺序颠倒urls.py为:

    url(r'^api/', include('snippets.apiurls')),
    url(r'^api/', include(router.urls)),

然后我被snippets列出但没有users

我猜 Django 正在服务于第一个匹配的路由。

除非有人能告诉我,否则我似乎需要一个路由器变量来传递并以某种方式添加。

4

4 回答 4

15

要在同一个 API 根目录中获取所有应用程序,您需要使用相同的 DefaultRouter 注册所有应用程序。

实现此目的的一种方法是制作一个自定义路由器,它拦截注册调用并将其传播到共享路由器。然后,您可以使用此共享路由器获取 api url。

class SharedAPIRootRouter(SimpleRouter):
    shared_router = DefaultRouter()

    def register(self, *args, **kwargs):
        self.shared_router.register(*args, **kwargs)
        super().register(*args, **kwargs)
        # if not py3: super(SharedAPIRootRouter, self).register(*args,**kwargs)

然后在每个应用程序中:

# in app1/urls.py 
router = SharedAPIRootRouter()
router.register(r'app1', App1ModelViewSet)

# in app2/urls.py
router = SharedAPIRootRouter()
router.register(r'app2', App2ModelViewSet)

在您的主 urls.py 中,您必须确保导入应用程序 url,以便在我们要求 shared_router.urls 之前进行注册

import app1.urls
import app2.urls

def api_urls():
    return SharedAPIRootRouter.shared_router.urls

urlpatterns = patterns(
    '',
    url(r'^api/', include(api_urls())),   
)   

如果您不想显式导入 url,则可以按约定进行:

def api_urls():
    from importlib import import_module
    for app in settings.INSTALLED_APPS:
        try:
            import_module(app + '.urls')
        except (ImportError, AttributeError):
            pass
    return SharedAPIRootRouter.shared_router.urls
于 2014-03-27T10:05:57.213 回答
6

这可以通过传递单个路由器实例来实现,如下所示。

在您的项目文件夹中创建一个名为router.py或类似的文件:main

from rest_framework import routers
common_router = routers.DefaultRouter()

在每个应用程序的urls.py放置:

from main.router import common_router as router
router.register(r'myapp-model-name', MyAppViewSet) 

在你的main urls.py地方:

import my_app1.urls  # to register urls with router
import my_app2.urls  # to register urls with router
...
# finally import router that includes all routes
from main.router import common_router

urlpatterns = [
    ...
    url(r'^api/', include(common_router.urls)),
    ...
]
于 2016-06-06T11:19:21.317 回答
5

这两种选择都是可能的。您可以在每个应用程序中公开routerurls,并将它们合并到您的全局urls. 我通常更喜欢使用urls(选项 2),因为它为每个应用程序提供了更大的灵活性:您可以根据需要定义额外的非 api URL。

选项1

在您的全局urls.py中:

from app1.api.routers import router1
from app2.api.routers import router2

urlpatterns = patterns('',
    url(r'^snippets/', include('snippets.urls', namespace="snippets"))
    ...
    url(r'^app1/api/', include(router1.urls)),
    url(r'^app2/api/', include(router2.urls)),
)

您可以轻松地为两个路由器使用相同的端点(只要您注意不要使用冲突的路由):

urlpatterns = patterns('',
    url(r'^snippets/', include('snippets.urls', namespace="snippets"))
    ...
    url(r'^api/', include(router1.urls)),
    url(r'^api/', include(router2.urls)),
)

选项 2

appN/api/urls.py

router = DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(include('app1.apis')

urlpatterns = patterns('',
    url(r'^', include(router.urls)),
    url(r'^misc/', some_other_view),
)

在您的全局urls.py中:

urlpatterns = patterns('',
    url(r'^snippets/', include('snippets.urls', namespace="snippets"))
    ...
    url(r'^api/', include('app1.api.urls')),
    url(r'^api/', include('app2.api.urls')),
)

请注意,urls模块不需要与urls标准视图的模块相同。

于 2013-12-29T13:29:16.243 回答
0

作为@Grischa的一个更高级的变体,我喜欢扩展他的方法:

在主要的routers.py

from rest_framework import routers

api_v1_router = routers.SimpleRouter()

在主要的urls.py

from django.urls import include, path

import app1.urls
from .routers import api_v1_router

# Register app urls
app1.urls.register(api_v1_router)
app2.urls.register(api_v1_router)
...

urlpatterns = [
    ...
    path('v1/', include((api_v1_router.urls, 'v1'))),
    ...
]

在每个应用程序的urls.py

from main.routers import api_v1_router
from .apis import MyAppViewSet1, MyAppViewSet2


def register(router):
    router.register(r'myapp-model-name1', MyAppViewSet1)
    router.register(r'myapp-model-name2', MyAppViewSet2)

这种方法的两个优点:

  1. 您可以在主程序中控制应用程序的注册urls.py
  2. 的灵活性register(router)允许您注册到不同的路由器,例如在同时使用 v1 和 v2 进行版本控制时。
于 2020-04-17T10:23:31.803 回答