I have come across a problem regarding having the API apps seperate, while still being able to use the browsable API for navigation.
I have previously used a seperate routers.py
file in my main application containing the following extension of the DefaultRouter
.
class DefaultRouter(routers.DefaultRouter):
def extend(self, router):
self.registry.extend(router.registry)
Followed by adding the other application routers like this:
from . routers import DefaultRouter
from app1.urls import router as app1_router
# Default Router
mainAppRouter = DefaultRouter()
mainAppRouter.extend(app1_router)
where the app1_router
is a new SimpleRouter
object.
Now the problem occurs when I want to modify the SimpleRouter
and create my own App1Router
, such as this
class App1Router(SimpleRouter):
routes = [
Route(
url = r'^{prefix}{trailing_slash}$',
mapping = {
'get': 'retrieve',
'post': 'create',
'patch': 'partial_update',
},
name = '{basename}-user',
initkwargs = {}
),
]
This will not handle my extension correctly. As an example, GET
and PATCH
are not recognized as allowed methods whenever I extend the router, but when I dont extend, but only use the custom router, everything works fine.
My question is therefor, how can I handle extending custom routers across seperate applications, but still maintain a good browsable API?
DefaultRouter. This router is similar to SimpleRouter as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional . json style format suffixes.
APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.
ModelViewSet. The ModelViewSet class inherits from GenericAPIView and includes implementations for various actions, by mixing in the behavior of the various mixin classes. The actions provided by the ModelViewSet class are .list() , .retrieve() , .create() , .update() , .partial_update() , and .destroy() .
queryset - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set read_only=True . many - If applied to a to-many relationship, you should set this argument to True .
The router registry is just a standard python list, so you can call YourRouter.registry.extend() directly on registy withouth the need to subclass the DefaultRouter, check the source of DRF here . Since registry is a list, when you extend registry you add another python list on top of python list, which implies calling YourRouter.registry.extend(app_router.registry). What worked for me, was importing routers from another apps (SimpleRouters) and adding them on top of default router registry.
#aplication_root/urls.py
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from app_3.urls import router as app_3_router
router = DefaultRouter()
router.registry.extend(app_3_router.registry)
urlpatterns = [
path('api/', include(router.urls)),
]
If your are trying to add versioning to your app by adding the prefix, I suggest to take a look at versioning schema available in DRF - maybe it could fit your needs DRF versioning
for example with URLPathVersioning enabled in your settings
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning'
}
urlparttern list from snipped above would look like that
urlpatterns = [
path('api/<version>/', include(router.urls)),
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With