Django Rest框架和字段级权限

Django Rest框架和字段级权限,django,rest,django-rest-framework,Django,Rest,Django Rest Framework,我想构建一个具有字段级权限的API。我从数据库表中获得这些权限,但在REST框架中,哪里可以检查用户是否可以对对象的字段执行CRUD操作 database --- model ---- ModelSerializer ---- ModelViewSet --- browser 在ModelSerializer中?在这里,我可以在字段到达视图集之前删除它们,但默认情况下我没有访问request.user的权限,因此我必须实现这一点,这可以做到,但与我拥有的其他第三方库(django rest s

我想构建一个具有字段级权限的API。我从数据库表中获得这些权限,但在REST框架中,哪里可以检查用户是否可以对对象的字段执行CRUD操作

database --- model ---- ModelSerializer ---- ModelViewSet --- browser
在ModelSerializer中?在这里,我可以在字段到达视图集之前删除它们,但默认情况下我没有访问request.user的权限,因此我必须实现这一点,这可以做到,但与我拥有的其他第三方库(django rest swagger)不起作用

还是在ModelViewset中?在这里,我可以覆盖列表、创建、更新和销毁方法,以删除用户无权访问的字段。但这不适合我的元数据实现,因为它直接从序列化程序获取元数据


或者两者兼而有之?例如:当序列化程序获取模型时,删除序列化程序中不允许的读取,并在将不允许的写入传递回序列化程序之前删除视图集中不允许的写入

DRF文档中有一个关于权限的好章节。处理(和检查)它们的好地方是在视图集中。要从文档中复制示例,请执行以下操作:

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

如果您想要自定义权限检查器,可以定义自己的,并使用自己的类指定替换
IsAuthenticated
,您可以根据特定请求所需的字段创建不同的序列化程序。然后您需要覆盖视图中的
get\u serializer\u class()
函数,并根据您的逻辑决定序列化程序

根据上的DRF文件

可以重写以提供动态行为,例如使用不同的 用于读写操作的序列化程序,或提供不同的 为不同类型的用户提供序列化程序

例如:

class MyView(..):

    def get_serializer_class(self):
        if self.request.user.is_staff: # check if staff user
            return FullAccountSerializer 
        return BasicAccountSerializer
    ... 

如果要实现自定义权限,最好在DRF中使用modelviewset

from rest_framework import status, viewsets

class MyModelViewsets(viewsets.ModelViewSet):
    queryset = # queryset
    serializer_class = # serializer class
    permission_classes = (# custom permission class her)
如果要将所有自定义权限应用于所有端点,请在settings.py中指定它

REST_FRAMEWORK = {

    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
        # add custom permission here
    ]
}

如果您使用的是GenericView,默认情况下,DRF会将请求对象放入序列化程序对象的上下文中。您可以通过以下方式访问用户信息:

self.context['request'].user

from utils.mixins import MultiSerializerViewSetMixin


class UserViewSet(MultiSerializerViewSetMixin, ModelViewSet):
    serializer_class = UserSerializer
    serializer_action_classes = {
        'update': UserDetailSerializer,
    }
    permission_classes = (UserPermission,)
    queryset = User.objects.all()
MultiSerializerViewSetMixin的源代码:

我用两个职业球员解决了我的问题:

from django.contrib.auth.models import User
from rest_framework import serializers


class UserSerializerMixin(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    is_superuser = serializers.BooleanField(read_only=True)
    first_name = serializers.CharField(max_length=30, required=False, allow_blank=True)
    last_name = serializers.CharField(max_length=30, required=False, allow_blank=True)
    email = serializers.EmailField(required=False, allow_blank=True)

    def create(self, validated_data):
        return User.objects.create_user(**validated_data)

    def update(self, instance, validated_data):
        instance.first_name = validated_data.get('first_name', instance.first_name)
        instance.last_name = validated_data.get('last_name', instance.last_name)
        instance.email = validated_data.get('email', instance.email)
        password = validated_data.get('password', '')
        if password:
            instance.set_password(password)
            instance.save()
        return instance

    class Meta:
        model = User


class UserSerializer(UserSerializerMixin):
    username = serializers.CharField(max_length=30)
    password = serializers.CharField(
        max_length=128, write_only=True,
        style={'input_type': 'password'})


class UserDetailSerializer(UserSerializerMixin):
    username = serializers.CharField(read_only=True)
    password = serializers.CharField(
        max_length=128, write_only=True,
        style={'input_type': 'password'},
        required=False, allow_blank=True
    )
您可以使用MultiSerializerViewSetMixin,我在去年的工作中发现它,并使用mixin创建两个不同但相似的序列化程序