Return the current user with Django Rest Framework
Question:
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.
Answers:
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,
...
})
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())
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.
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,
...
})
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())