Home > Enterprise >  How to Nest URL routes in Django Rest Framework (DRF) RetrieveUpdateDestroyAPIView without router
How to Nest URL routes in Django Rest Framework (DRF) RetrieveUpdateDestroyAPIView without router

Time:02-20

I am using the Django rest framework and RetrieveUpdateDestroyAPIView and trying to Implement nested URL patterns.

# my current URLs structure is like
/api/v1/kitchens/ - ListCreateAPIView
/api/v1/kitchens/1/ - RetrieveUpdateDestroyAPIView
/api/v1/orders/ - ListCreateAPIView
/api/v1/orders/1/ - RetrieveUpdateDestroyAPIView
/api/v1/items/ - ListCreateAPIView
/api/v1/items/1/ - RetrieveUpdateDestroyAPIView

The above structure works fine with all the operations but to get the list of items or orders under a single kitchen I am trying to achieve something live below.

the views.py has something like below.

class KitchenListView(generics.ListCreateAPIView):
  queryset = Kitchen.objects.all()
  serializer_class = KitchenSerializer
  pagination_class = LimitOffsetPagination
  permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
  authentication_classes = (TokenAuthentication,)
  filter_backends = (DjangoFilterBackend,)
  filter_fields = ("user",)


class KitchenDetailView(generics.RetrieveUpdateDestroyAPIView):
  queryset = Kitchen.objects.all()
  serializer_class = KitchenDetailsSerializer
  permission_classes = (
    permissions.IsAuthenticatedOrReadOnly,
    IsOwnerOrReadOnly,
  )
 authentication_classes = (TokenAuthentication,)

# I want to create this structure.
/api/v1/kitchens/ - List
/api/v1/kitchens/1/ - Details
/api/v1/kitchens/1/orders/ - Orders List
/api/v1/kitchens/1/orders/1/ - Order Details
/api/v1/kitchens/1/items/ - Items List
/api/v1/kitchens/1/items/1/ - Item Details

I am trying to achieve something like this. Please suggest to me the better solution if anyone has and what would be better to go with generic API views or Viewsets as my project is a large-scale project.

Thanks in Advance.

CodePudding user response:

First of all, I'm assuming that you have Order view and Item view; in both of your views try this:

from rest_framework.generics import get_object_or_404


class OrderListView(generics.ListCreateAPIView):
    ...
   
    def get_queryset(self):
        if self.kwargs.get('kitchen_pk'):
            return self.queryset.filter(kitchen_id=self.kwargs.get('kitchen_pk'))
        return self.queryset.all()

class OrderDetailView(generics.RetrieveUpdateDestroyAPIView):
    ...

    def get_object(self):
        if self.kwargs.get('kitchen_pk'):
            return get_object_or_404(self.get_queryset(), kitchen_id=self.kwargs.get('kitchen_pk'), pk=self.kwargs.get('order_pk')) 
        return get_object_or_404(self.get_queryset(), pk=self.kwargs.get('order_pk'))


class ItemListView(generics.ListCreateAPIView):
    ...
   
    def get_queryset(self):
        if self.kwargs.get('kitchen_pk'):
            return self.queryset.filter(kitchen_id=self.kwargs.get('kitchen_pk'))
        return self.queryset.all()

class ItemDetailView(generics.RetrieveUpdateDestroyAPIView):
    ...

    def get_object(self):
        if self.kwargs.get('kitchen_pk'):
            return get_object_or_404(self.get_queryset(), kitchen_id=self.kwargs.get('kitchen_pk'), pk=self.kwargs.get('item_pk'))  
        return get_object_or_404(self.get_queryset(), pk=self.kwargs.get('item_pk'))
       

In your urls.py:

urlpatterns = [
    path('kitchens/', KitchenListView.as_view(), name='kitchens'),
    path('kitchens/<int:pk>/', KitchenDetailView.as_view(), name='kitchen'),

    path('kitchens/<int:kitchen_pk>/orders/', OrderListView.as_view(), name='kitchen_orders'),
    path('kitchens/<int:kitchen_pk>/orders/<int:order_pk>/', OrderDetailView.as_view(), name='kitchen_order'),

    path('kitchens/<int:kitchen_pk>/items/', ItemListView.as_view(), name='kitchen_items'),
    path('kitchens/<int:kitchen_pk>/items/<int:item_pk>/', ItemDetailView.as_view(), name='kitchen_item'),
]

I don't know if it will work but it is a beginning!

  • Related