Return the current user with Django Rest Framework

2019-03-08 01:44发布

I am currently developping an API using Django.

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

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

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

Do you have any idea ?

5条回答
疯言疯语
2楼-- · 2019-03-08 01:49

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(UserViewSet, self).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):
    # ...
查看更多
Juvenile、少年°
3楼-- · 2019-03-08 01:49

I used a ModelViewSet like this:

class UserViewSet(viewsets.ModelViewSet):
    model = User
    serializer_class = UserSerializer

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

        return super(UserViewSet, self).dispatch(request, *args, **kwargs)
查看更多
萌系小妹纸
4楼-- · 2019-03-08 02:03

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.

查看更多
萌系小妹纸
5楼-- · 2019-03-08 02:03

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

class UserViewSet(viewsets.ModelViewSet):
    model = User
    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.

查看更多
聊天终结者
6楼-- · 2019-03-08 02:10

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,)
    queryset = User.objects.all()
    serializer_class = UserSerializer

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

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

查看更多
登录 后发表回答