在Django Rest框架中自定义权限和响应详细信息



概述 - 我正在创建一个Django REST API,该API从嵌套的URL路由返回数据。到目前为止,我发现这样做的最好方法是将URL Regexes手动添加到URLS.PY,然后在我的视图中使用@Detail_Route来检索过滤的序列化器数据。

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

如何自定义详细信息来执行此操作?例如:

如果用户是管理员,他们可以在/api/v2/用户URL上使用" post"方法。如果他们没有认证,则会得到不良请求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'),
]

serializer.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)

就嵌套路由而言,我建议您查看drf-nest-nest-nest-nest-nest-nest-nest-nest-nest-router套件或类似的内容,它往往会使您的生活更轻松SimpleRouterNestedSimpleRouter类。

如果用户是管理员,他们可以在/api/v2/用户URL上使用" post"方法。如果他们没有认证,他们会得到不良请求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

因此,例如,如果您想通过路由器或通过urls.py上的{'get': 'list'}链接GET /api/v2/users/,则可以基于用户覆盖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

在这种情况下,您也可以通过允许使用SAFE_METHODS的任何人来使用UserViewSetpermission_classes参数,否则检查admin状态:

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,)
    ...

我可能迟到了聚会,但希望这将来会对他人有所帮助。

相关内容

最新更新