Search code examples
djangodjango-rest-frameworkdjango-rest-viewsets

django-rest-framework custom viewset retrive with multiple lookup args


I have two models say A and B.

models look like

class A(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)
    slug = models.CharField(max_length=100)

class B(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)
    slug = models.CharField(max_length=100)
    A = models.foreignkey(A, models.SET_NULL, blank=true)

serializers

Class ASerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
         model = A
         fields = '__all__'
         lookup_field = 'slug'
         extra_kwargs = {'url': {'lookup_field': 'slug'}}


Class BSerializer(serializers.ModelSerializer):
    class Meta:
         model = B
         fields = '__all__'

model viewset

from rest_framework import viewsets, permissions
from rest_framework.response import Response
from rest_framework.decorators import action
from .models import (A, B)
from .serializers import (ASerializer, BSerializer)


Class AViewSet(viewsets.ModelViewSet):
     queryset = A.objects.all()
     serializer_class = ASerializer
     permission_classes =                           (permissions.DjangoModelPermissionsOrAnonReadOnly, )
     lookup_field = 'slug'

     def retrieve(self, request, *args, **kwargs):
          instance = self.get_object()
          bs = B.objects.filter(A=instance.id)
          serializer = BSerializer(bs, many=True)

          return Response(serializer.data)

I want to access a url something like

Url: ^A/<slug>/B/slug>/$

I go through Django Restframework documention and found that we can add custom url like ( drf-custom-rounting. I don't get how to make access url pattern above.

How to customize like that?

EDIT: I have solved my problem. I found a similar type of problem solution here. Thank you for all your response.


Solution

  • I think what you are looking for is a way to make nested urls.

    Recommanded way by DRF doc is using this package : https://github.com/alanjds/drf-nested-routers

    Usage example :

    First you create your viewset :

    Class BViewSet(viewsets.ModelViewSet):
         queryset = B.objects.all()
         serializer_class = BSerializer
         lookup_field = 'slug'
    
         def retrieve(self, request, a_slug=None, b_slug=None):
              a = self.get_object()
              # Now you retrieve all B related to A
              bs = B.objects.filter(A=a)
              serializer = BSerializer(bs, many=True)
              return Response(serializer.data)
    

    Then you register your viewset using drf-nested-routers :

    from rest_framework_nested import routers
    
    from .viewsets import AViewSet, BViewSet
    
    a_router = routers.SimpleRouter()
    a_router.register(r'A', AViewSet)
    
    b_router = routers.NestedSimpleRouter(a_router, r'B')
    b_router.register(r'B', BViewSet)
    
    urlpatterns = patterns('',
        url(r'^', include(a_router.urls)),
        url(r'^', include(b_router.urls)),
    )