Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest required parameters in URL

Tags:

I'm using django rest framework. Here is my code:

urls.py:

urlpatterns = [
    url(r'^users/show', UserShow.as_view()),
]

view.py:

class UserShow(ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get_queryset(self):
        queryset = User.objects.all()
        username = self.request.query_params.get('username', None)
        user_id = self.request.query_params.get('user_id', None)
        if username is not None:
            queryset = queryset.filter(username=username)
        if user_id is not None:
            queryset = queryset.filter(pk=user_id)
        return queryset

I want to get values from url like this: /users/show?user_id=1 or /users/show?username=mike.

Either an user_id or username must be required parameter. How can I control it in class based views?

With my code if I'm sending the request with wrong parameter name /users/show?user111name=mike or simple /users/show the view of course response me with queryset = User.objects.all() and lists all the users. I don't need that. I need if required parameters are None response with 404.

I can get needed result with function based view:

@api_view(['GET'])
def users(request):
    if request.method == 'GET':
        queryset = User.objects.all()
        username = request.GET.get('username', None)
        user_id = request.GET.get('user_id', None)

        if username is not None:
            queryset = queryset.filter(username=username)
        elif user_id is not None:
            queryset = queryset.filter(pk=user_id)
        else:
            return Response({"status": "required field not found."},
                            status=status.HTTP_404_NOT_FOUND)

        if not queryset.exists():
            return Response({"status": "not found."},
                            status=status.HTTP_404_NOT_FOUND)

        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

But how can I do it with generic class based views?

like image 339
arstj Avatar asked May 27 '16 13:05

arstj


1 Answers

class UserIdRetrieve(RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

class UserUsernameRetrieve(UserIdRetrieve):
     lookup_field = 'username'

and in urls:

urlpatterns = [
    url(r'^users/(?P<pk>\d+)/', UserIdRetrieve.as_view()), 
    url(r'^users/by-username/(?P<username>\w+)/', UserUsernameRetrieve.as_view())
]

if your url structure is a must, small change to above:

class UserIdRetrieve(RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    def get_object(self):
        queryset = self.filter_queryset(self.get_queryset())

        if 'username' in self.request.query_params:
            filter_kwargs = {'username': self.request.query_params['username']}
        elif 'user_id' in self.request.query_params:
             filter_kwargs = {'id': self.request.query_params['user_id']}
        else:
            raise Http404('Missing required parameters')

        obj = get_object_or_404(queryset, **filter_kwargs)

        # May raise a permission denied
        self.check_object_permissions(self.request, obj)

        return obj

and in urls:

urlpatterns = [
    url(r'^users/show', UserRetrieve.as_view())
]
like image 141
Jerzyk Avatar answered Nov 15 '22 00:11

Jerzyk