Using Nested Routers DRF-Nested Routers in Django Rest framework

Thuc Pham
The Startup
Published in
3 min readSep 9, 2020

Introduction

The article introduces how to use DRF-Nested-Routers framework https://github.com/alanjds/drf-nested-routers to create URLs for nested resources. In this tutorial, our target is to create APIs for getting libraries and books.

/api/libraries/ -> Get list of libraries
/api/libraries/{library_id}/books/ -> Get list of book in a library
/api/libraries/{library_id}/books/{book_id} -> Get details of a book

Diagram

The ERD of the project

Problem

Django Rest Framework supports to generate the URL by using Routers.

REST framework adds support for automatic URL routing to Django, and provides you with a simple, quick and consistent way of wiring your view logic to a set of URLs.

Here’s an example of a simple URF conf using SimpleRouter according to Django Rest Framework document.

from django.urls import path, include
from rest_framework import routers
from library import views
router = routers.SimpleRouter()
router.register('libraries', views.LibraryViewSet)
router.register('books',views.BookViewSet)
urlpatterns = [
path('', include(router.urls)),
]

By using the ViewSet, Django automatically generates these URLs under the hood:

  • URL pattern: ^libraries/$ Name: 'library-list'
  • URL pattern: ^librariess/{pk}/$ Name: 'library-detail'
  • URL pattern: ^books/$ Name: 'book-list'
  • URL pattern: ^books/{pk}/$ Name: 'book-detail'

However, our target is to create the nested URL pattern ^librariess/{library_pk}/books/$ to get the list of books within a library and ^librariess/{library_pk}/books/{book_pk}/$ to get details of a book.

To do in Django, you have to explicitly define the URL pattern using a regular expression. In this case, the library_pk is an integer, so we can use \d+. If it is a string, you can use \w.

# Get list of books in a library
url(r'^libraries/(?P<library_pk>\d+)/books/?$', views.BookViewSet.as_view({'get': 'list'}), name='library-book-list')
# Get details of a book in a library
url(r'^libraries/(?P<library_pk>\d+)/books/(?P<pk>\d+)/?$', views.BookViewSet.as_view({'get': 'retrieve'}), name='library-book-detail')

Now you have to get the library_pk in the BookViewSet and get the books based on that ID

class BookViewSet(viewsets.ModelViewSet):
"""Viewset of book"""
queryset = Book.objects.all().select_related(
'library'
).prefetch_related(
'authors'
)
serializer_class = BookSerializer

def get_queryset(self, *args, **kwargs):
library_id = self.kwargs.get("library_pk")
try:
library = Library.objects.get(id=library_id)
except Library.DoesNotExist:
raise NotFound('A library with this id does not exist')
return self.queryset.filter(library=library)

Done. You can get access to the URL api/libraries/{library_pk}/books and api/libraries/{library_pk}/books/{book_pk}/ in your browser now.

But imagine if your project scale-up and you have to implement many relational nested URLs, your code is likely not easy to read. There is an alternative way which is to use DRF-Nested-Routers framework.

Install DRF-Nested-Routers

You can install the library by using pip

pip install drf-nested-routers

Usage

By using DRF-Nested-Routers, the URL pattern will be simplified. It also increases the readability of the code.

from rest_framework_nested import routersrouter = SimpleRouter()
router.register('libraries', views.LibraryViewSet)
book_router = routers.NestedSimpleRouter(
router,
r'libraries',
lookup='library')
book_router.register(
r'books',
views.BookViewSet,
basename='library-book'
)
app_name = 'library'urlpatterns = [
path('', include(router.urls)),
path('', include(book_router.urls)),
]

Conclusion

Again it depends on the requirement of your API to make a decision whether or not to use the DRF-Nested-Routers. The regular expression pattern itself is not very too hard to understand, so you can use it if you don’t have many nested relational URLs.

Happy coding. If you have any queries, feel free to contact me. I am happy to discuss and connect with you.

Twitter: https://twitter.com/steve_pham93

Email: duythuc28493@gmail.com

Download the full project

https://github.com/stevethucpham/demo-django-drf-nested-router

--

--