Registering API in apps

前端 未结 4 1693
独厮守ぢ
独厮守ぢ 2021-02-04 10:46

With django-rest-framework I\'m using the DefaultRouter

I want to provide APIs to several apps, so my question is can I do this in a django manner and put m

相关标签:
4条回答
  • 2021-02-04 11:02

    As a more advanced variant on @Grischa, I like to extend his approach:

    In the main's routers.py:

    from rest_framework import routers
    
    api_v1_router = routers.SimpleRouter()
    

    In the main's 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'))),
        ...
    ]
    

    In each app's 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)
    

    Two advantages of this approach:

    1. You can control the registration of the apps in the main urls.py
    2. The flexibility of register(router) allows you to register to different routers, for example when using both v1 and v2 for versioning.
    0 讨论(0)
  • 2021-02-04 11:07

    Both options are possible. You can either expose the router or the urls in each app, and merge those into your global urls. I usually prefer using urls (option 2) because it gives more flexibility in each app: you can define extra non-api URLs as needed.

    Option 1

    In your global 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)),
    )
    

    You can as easily use the same endpoint for both routers (as long as you're careful not to use conflicting routes):

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

    Option 2

    In 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),
    )
    

    In your global 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')),
    )
    

    Note that the urls modules do not need to be the same as the urls for standard views.

    0 讨论(0)
  • 2021-02-04 11:11

    To get all apps in the same API root, you need to register all your apps with the same DefaultRouter.

    One way to achieve this is to make a custom router, which intercepts the register call and propagates it to a shared router. You then use this shared router to get the api urls.

    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)
    

    Then in each app:

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

    In your main urls.py, you must ensure you import the app urls so that registration occurs before we ask for 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())),   
    )   
    

    if you do not want to import the urls explicitly, you can do it by convention:

    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
    
    0 讨论(0)
  • 2021-02-04 11:18

    This is possible by passing around a single router instance as follows.

    Create a file called router.py or similar in your main project folder:

    from rest_framework import routers
    common_router = routers.DefaultRouter()
    

    In each app's urls.py put:

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

    In your main 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)),
        ...
    ]
    
    0 讨论(0)
提交回复
热议问题