Регистрация API в приложениях
С django-rest-framework я использую DefaultRouter
Я хочу предоставить API-интерфейсы нескольким приложениям, поэтому мой вопрос: могу ли я сделать это с помощью django и разместить регистрацию маршрутизаторов в каждом URL-адресе приложения и показать их как один агрегированный api или идеально в пространстве имен.
Другими словами, если app1
содержит modelA
и modelB
, а app2
содержит modelC
:
- Могу ли я объявить 2 маршрутизатора, которые появляются в
mysite/app1/api
и mysite/app2/api
, или
- Могу ли я иметь один api в
mysite/api
, который перечисляет все три модели, но регистрирует отдельные модели в своем собственном приложении urls.py
Что-то вроде
router = DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(include('app1.apis')
router.register(include('app2.apis')
В качестве альтернативы есть простой способ, с помощью которого моя переменная маршрутизатора может быть доступна в каждом URL-адресе приложения, чтобы они могли вызывать router.register
? Я не уверен, что
urlpatterns = patterns('',
url(r'^snippets/', include('snippets.urls', namespace="snippets"))
...
url(r'^api/', include(router.urls)),
действительно вызывает выполнение кода в app1/urls.py
в этой точке, чтобы он мог вызвать router.register
каким-то образом, так что окончательный URL-адрес включает в себя все регистрации приложений, а также один проект.
UPDATE
Используя вариацию на Nicolas Cortot option 2
, я получаю свой конкретный ресурс API
для работы, но он не указан в качестве доступного ресурса в root API
в myserver\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 выполняет первый сопоставленный маршрут.
Если кто-то не может сказать мне иначе, мне, похоже, нужна одна переменная маршрутизатора, которая должна быть передана и добавлена к каким-то образом.
Ответы
Ответ 1
Чтобы получить все приложения в одном корневом каталоге API, вам необходимо зарегистрировать все приложения с тем же DefaultRouter.
Одним из способов достижения этого является создание настраиваемого маршрутизатора, который перехватывает вызов регистра и передает его на общий маршрутизатор. Затем вы используете этот общий маршрутизатор для получения api-адресов.
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
Ответ 2
Возможны оба варианта. Вы можете либо показать router
, либо urls
в каждом приложении и объединить их в свой глобальный urls
. Обычно я предпочитаю использовать urls
(вариант 2), потому что он дает большую гибкость в каждом приложении: вы можете определить дополнительные URL-адреса, отличные от api, по мере необходимости.
Вариант 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
для стандартных представлений.
Ответ 3
Это возможно, передав один экземпляр маршрутизатора следующим образом.
Создайте файл с именем router.py
или похожим в вашей основной папке проекта:
from rest_framework import routers
common_router = routers.DefaultRouter()
В каждом приложении urls.py
put:
from main.router import common_router as router
router.register(r'myapp-model-name', MyAppViewSet)
В главном urls.py
put:
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)),
...
]