【问题标题】:Customizing permissions and responses for detail routes in Django rest framework在 Django rest 框架中自定义详细路由的权限和响应
【发布时间】:2018-05-14 12:22:45
【问题描述】:

概述 - 我正在创建一个 Django REST API,它从嵌套的 url 路由返回数据。到目前为止,我发现做到这一点的最佳方法是手动将 url 正则表达式添加到 urls.py 中,然后在我的视图中使用 @detail_route 来检索过滤后的序列化程序数据。

现在我有用户对象和目标对象,它们需要基于身份验证等不同的数据响应......

如何自定义详细路线来做到这一点?例如:

如果用户是管理员,他们可以在 /api/v2/users 网址中使用“发布”方法。如果他们未通过身份验证,他们会收到错误的请求 400 响应。

如果用户是管理员,他们可以使用“get”方法检索所有用户名、电子邮件和密码,但如果不是,他们只能获取用户名。

urls.py

urlpatterns = [

    url(r'^api/v2/users/$',
        UserViewSet.as_view({'get': 'users', 'post': 'users', 'put': 'users',
                             'patch': 'users', 'delete': 'users'}),
        name='user_list'),

    url(r'^api/v2/user/(?P<uid>\d+)/goals/$',
        UserViewSet.as_view({'get': 'user_goals', 'post': 'user_goals', 'put': 'user_goals',
                             'patch': 'user_goals', 'delete': 'user_goals'}),
        name='user_goals_list'),
]

序列化器.py

class GoalSerializer(serializers.ModelSerializer):
    class Meta:
        model = Goal
        fields = ('id', 'user_id', 'name', 'amount',
                  'start_date', 'end_date', )


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('username', 'email', 'id', 'password')
        read_only_fields = ('id', )
        extra_kwargs = {'password': {'write_only': True}}

views.py

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

    @detail_route(methods=['get', 'post', 'delete', 'put', 'patch', ])
    def users(self, request):
        users = User.objects.all()
        serializer = serializers.UserSerializer(
            users, many=True
        )
        return Response(serializer.data)

    @detail_route(methods=['get', 'post', 'delete', 'put', 'patch', ])
    def user_goals(self, request, uid):
        goals = Goal.objects.filter(user_id=uid)
        serializer = serializers.GoalSerializer(
            goals, many=True
        )
        return Response(serializer.data)

    @detail_route(methods=['get', 'post', 'delete', 'put', 'patch', ])
    def user_goal_detail(self, request, uid, gid):
        goal = Goal.objects.filter(user_id=uid, id=gid)
        serializer = serializers.GoalSerializer(
            goal, many=True
        )
        return Response(serializer.data)

【问题讨论】:

    标签: django django-rest-framework django-views


    【解决方案1】:

    就嵌套路由而言,我建议您查看drf-nested-routers 包或类似的包,它会使您的路由工作更轻松,请查看SimpleRouterNestedSimpleRouter 类。

    如果用户是管理员,他们可以在 /api/v2/users 网址中使用“发布”方法。如果他们未通过身份验证,他们会收到错误的请求 400 响应。

    @detail_route 装饰器可以接收permission_classes 参数,您可以在其中指定执行声明的操作所需的权限,就像您正在使用的ViewSet

    但是,您的示例显示了 User 模型的 ModelViewSet,这意味着您已经公开了多个操作,以及多个 GenericViewSet 相关奖金(get_serializerget_object 等):

    class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass
    

    因此,例如,如果您想要执行GET /api/v2/users/,通过路由器或通过urls.py 上的{'get': 'list'} 链接它,您可以根据用户覆盖get_serializer_class 方法:

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
    
        You may want to override this if you need to provide different
        serializations depending on the incoming request.
    
        (Eg. admins get full serialization, others get basic serialization)
        """
        assert self.serializer_class is not None, (
            "'%s' should either include a `serializer_class` attribute, "
            "or override the `get_serializer_class()` method."
            % self.__class__.__name__
        )
    
        return self.serializer_class
    

    在这种情况下,您还可以使用UserViewSetpermission_classes 参数,允许任何人使用SAFE_METHODS,否则检查管理员状态:

    from rest_framework.permissions import BasePermission, SAFE_METHODS
    
    class IsAdminOrReadOnly(BasePermission):
    
        def has_permission(self, request, view):
            if request.method in SAFE_METHODS:
                return True
    
            return request.user and request.user.is_staff
    
    class UserViewSet(viewsets.ModelViewSet):
        queryset = User.objects.all()
        serializer_class = serializers.UserSerializer
        permission_classes = (IsAdminOrReadOnly,)
        ...
    

    我可能迟到了,但希望这对以后的其他人有所帮助。

    【讨论】:

      猜你喜欢
      • 2020-09-22
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 2021-01-30
      • 2016-01-10
      • 1970-01-01
      • 1970-01-01
      • 2016-01-01
      相关资源
      最近更新 更多