Home > other >  Django Rest Framework Viewset Filter By Value
Django Rest Framework Viewset Filter By Value

Time:07-27

Let's say I have a DRF viewset like so

    class SecretViewset(
        viewsets.ModelViewSet,
    ):
    
        queryset = Secret.objects.all()
        serializer_class = SecretSerializer
    
        @action(methods=['GET'], detail=True)
        def name(self, request, pk=None):
            secrets = Secret.objects.filter(name__contains=pk)
            return Response(self.get_serializer(secrets, many=True).data)

I want to be able to search via a name in the URL. So /api/secrets/name/NAMEHERE/

However, because ModelViewset implements mixins.Retrieve, it returns a 404 because it searches /api/secrets/ID/ first and doesn't find it, therefore throws a 404.

What would the proper way be to go about adding the ability to search by name as described above?

Edit

Adding my urls conf

from .Secret.viewsets import SecretViewset

router = routers.SimpleRouter()
router.register(r'^api/secrets', SecretViewset, 'secrets')

# Later on, router gets imported and added on via `urlpatterns  = router.urls`

CodePudding user response:

in yor urls.py put /api/secrets/name/NAMEHERE/ before /api/secrets/ID/

CodePudding user response:

You can do this using a simple APIView and a custom url path.

Code for the view:

class SecretRetrieveView(rest_framework.views.APIView):
    def get(self, request, *args, **kwargs):
        secrets = Secret.objects.filter(name__contains=kwargs['name'])
        return Response(SecretSerializer(secrets, many=True).data)

Code in your urls config: (Don't forget to import SecretRetrieveView!)

custom_urlpatterns = [
    path('/api/secrets/name/<str:name>/', SecretRetrieveView.as_view(), name='secret-retrieve'),
]

Finally, Make sure your urls conf looks like this

urlpatterns  = custom_urlpatterns
urlpatterns  = router.urls
  • Related