Return the current user with Django Rest Framework

I am currently developing an API using Django.

However, I would like to create a view that returns the current User with the following endpoint: /users/current/.

To do so, I created a list view and filtered the queryset on the user that made the request. That works, but the result is a list, not a single object. Combined with pagination, the result looks way too complicated and inconsistent compared to other endpoints.

I also tried to create a detail view and filtering the queryset, but DRF complains that I provided no pk or slug.

53242 次浏览

With something like this you're probably best off breaking out of the generic views and writing the view yourself.

@api_view(['GET'])
def current_user(request):
serializer = UserSerializer(request.user)
return Response(serializer.data)

You could also do the same thing using a class based view like so...

class CurrentUserView(APIView):
def get(self, request):
serializer = UserSerializer(request.user)
return Response(serializer.data)

Of course, there's also no requirement that you use a serializer, you could equally well just pull out the fields you need from the user instance.

@api_view(['GET'])
def current_user(request):
user = request.user
return Response({
'username': user.username,
'email': user.email,
...
})

Hope that helps.

I used a ModelViewSet like this:

class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
    

def dispatch(self, request, *args, **kwargs):
if kwargs.get('pk') == 'current' and request.user:
kwargs['pk'] = request.user.pk


return super().dispatch(request, *args, **kwargs)

If you must use the generic view set for some reason, you could do something like this,

class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer


def get_object(self):
return self.request.user


def list(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)

retrieve method is called when the client requests a single instance using an identifier like a primary key /users/10 would trigger the retrieve method normally. Retrieve itself calls get_object. If you want the view to always return the current used then you could modify get_object and force list method to return a single item instead of a list by calling and returning self.retrieve inside it.

Instead of using full power of ModelViewSet you can use mixins. There is RetrieveModelMixin used to retrieve single object just like it is mentioned here - http://www.django-rest-framework.org/api-guide/viewsets/#example_3

class UserViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = UserSerializer


def get_object(self):
return self.request.user

If you need also update your model, just add UpdateModelMixin.

The best way is to use the power of viewsets.ModelViewSet like so:

class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer


def get_object(self):
pk = self.kwargs.get('pk')


if pk == "current":
return self.request.user


return super().get_object()

viewsets.ModelViewSet is a combination of mixins.CreateModelMixin + mixins.RetrieveModelMixin + mixins.UpdateModelMixin + mixins.DestroyModelMixin + mixins.ListModelMixin + viewsets.GenericViewSet. If you need just list all or get particular user including currently authenticated you need just replace it like this

class UserViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
# ...

Use this way to get logged in user data in django rest framework

class LoggedInUserView(APIView):
def get(self, request):
serializer = UserSerializer(self.request.user)
return Response(serializer.data)

Add the api in urls.py file.

path('logged_in_user', LoggedInUserView.as_view())