【问题标题】:Return the current user with Django Rest Framework使用 Django Rest Framework 返回当前用户
【发布时间】:2013-03-24 02:58:17
【问题描述】:

我目前正在使用 Django 开发 API。

但是,我想创建一个视图,该视图返回具有以下端点的当前用户:/users/current/

为此,我创建了一个列表视图并过滤了发出请求的用户的查询集。这行得通,但结果是一个列表,而不是单个对象。结合分页,与其他端点相比,结果看起来过于复杂和不一致。

我还尝试创建详细视图并过滤查询集,但 DRF 抱怨我没有提供 pk 或 slug。

你有什么想法吗?

【问题讨论】:

    标签: python django api django-rest-framework


    【解决方案1】:

    在django rest框架中使用这种方式获取登录用户数据

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

    在 urls.py 文件中添加 api。

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

    【讨论】:

      【解决方案2】:

      您可以使用 mixins,而不是使用 ModelViewSet 的全部功能。就像这里提到的一样,有用于检索单个对象的 RetrieveModelMixin - 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
      

      如果您还需要更新模型,只需添加 UpdateModelMixin。

      【讨论】:

        【解决方案3】:

        最好的方法是像这样使用viewsets.ModelViewSet 的力量:

        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.ModelViewSetmixins.CreateModelMixin + mixins.RetrieveModelMixin + mixins.UpdateModelMixin + mixins.DestroyModelMixin + mixins.ListModelMixin + viewsets.GenericViewSet 的组合。如果您只需要列出所有或获取特定用户,包括当前经过身份验证的用户,您只需像这样替换它

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

        【讨论】:

          【解决方案4】:

          如果您出于某种原因必须使用通用视图集,您可以这样做,

          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 方法在客户端使用诸如主键/users/10 之类的标识符请求单个实例时调用,将正常触发检索方法。检索本身调用get_object。如果您希望视图始终返回当前使用的视图,则可以修改 get_object 并强制 list 方法返回单个项目而不是列表,方法是在其中调用并返回 self.retrieve

          【讨论】:

            【解决方案5】:

            我使用了这样的 ModelViewSet:

            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)
            

            【讨论】:

            • elb,我尝试使用上述函数,但似乎 dispatch() 运行得太早, request.user 仍然是匿名的,用户在调度运行后被分配.. 有什么替代方案吗?
            • 这个对我来说很好用。您可能希望将 request.user 更改为 request.user.is_authenticated()。因为如果你没有登录,request.userAnonymousUser
            • 与 SessionAuthentication 一起使用。使用 TokenAuthentication 时不起作用。 request.user 在 dispatch 中是匿名的。
            • 这不适用于令牌身份验证。执行身份验证的位置在 initial() 调用内部,并且在调度中完成,因此永远不会对使用进行身份验证。
            【解决方案6】:

            有了这样的东西,你可能最好打破通用视图并自己编写视图。

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

            你也可以像这样使用基于类的视图来做同样的事情......

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

            当然,你也不需要使用序列化器,你同样可以从用户实例中提取你需要的字段。

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

            希望对您有所帮助。

            【讨论】:

            • 注意:我必须使用serializer = UserSerializer(request.user, context={'request': request}),因为我的用户序列化程序包含一个超链接url 字段(基于默认项目)。
            猜你喜欢
            • 2022-06-12
            • 2022-01-17
            • 2020-07-23
            • 1970-01-01
            • 2014-10-27
            • 1970-01-01
            • 2019-08-19
            • 1970-01-01
            • 2015-11-16
            相关资源
            最近更新 更多