Django REST框架中的每字段权限

rav*_*shi 32 django django-rest-framework

我正在使用Django REST Framework来序列化Django模型.我有一个ListCreateAPIView视图列出对象和一个RetrieveUpdateDestroyAPIView视图来检索/更新/删除单个对象.该模型存储用户自己提交的信息.他们提交的信息包含一些私人信息和一些公共信息.我希望所有用户能够列出和检索公共信息,但我只希望所有者列出/检索/更新/删除私人信息.因此,我需要每个字段的权限而不是对象权限.

我找到的最接近的建议是https://groups.google.com/forum/#!topic/django-rest-framework/FUd27n_k3U0,它会根据请求类型更改序列化程序.这对我的情况不起作用,因为我当时没有查询集或对象来确定它是否归用户所有.

当然,我的前端隐藏了私人信息,但聪明的人仍然可以窥探API请求以获取完整的对象.如果需要代码,我可以提供它,但我的请求适用于vanilla Django REST Framework设计.

jho*_*jho 37

如何根据用户切换序列化程序类?

在文档中:

http://www.django-rest-framework.org/api-guide/generic-views/#get_serializer_classself

def get_serializer_class(self):
    if self.request.user.is_staff:
        return FullAccountSerializer
    return BasicAccountSerializer
Run Code Online (Sandbox Code Playgroud)

  • 完美的发现。谢谢你,先生。你让我的生活变得轻松。 (3认同)

Tod*_*dor 14

前几天我遇到了类似的问题.这是我的方法:

这是一个DRF 2.4解决方案.

class PrivateField(serializers.Field):
    def field_to_native(self, obj, field_name):
        """
        Return null value if request has no access to that field
        """
        if obj.created_by == self.context.get('request').user:
            return super(PrivateField, self).field_to_native(obj, field_name)
        return None

#Usage
class UserInfoSerializer(serializers.ModelSerializer):
    private_field1 = PrivateField()
    private_field2 = PrivateField()

    class Meta:
        model = UserInfo
Run Code Online (Sandbox Code Playgroud)

和DRF 3.x解决方案:

class PrivateField(serializers.ReadOnlyField):

    def get_attribute(self, instance):
        """
        Given the *outgoing* object instance, return the primitive value
        that should be used for this field.
        """
        if instance.created_by == self.context['request'].user:
            return super(PrivateField, self).get_attribute(instance)
        return None
Run Code Online (Sandbox Code Playgroud)

这次我们ReadOnlyField只是扩展,因为to_representation没有在serializers.Field类中实现.

  • @mcastle是的,我们终于有时间更新到新版本的DRF,因此提供了一个新的解决方案. (2认同)

Jul*_*ins 6

这里:

--models.py:

class Article(models.Model):
    name = models.CharField(max_length=50, blank=False)
    author = models.CharField(max_length=50, blank=True)

    def __str__(self):
        return u"%s" % self.name

    class Meta:
        permissions = (
            # name
            ('read_name_article', "Read article's name"),
            ('change_name_article', "Change article's name"),

            # author
            ('read_author_article', "Read article's author"),
            ('change_author_article', "Change article's author"),
        )
Run Code Online (Sandbox Code Playgroud)

-- 序列化器.py:

class ArticleSerializer(serializers.ModelSerializer):

    class Meta(object):
        model = Article
        fields = "__all__"

    def to_representation(self, request_data):
        # get the original representation
        ret = super(ArticleSerializer, self).to_representation(request_data)
        current_user = self.context['request'].user
        for field_name, field_value in sorted(ret.items()):
            if not current_user.has_perm(
                'app_name.read_{}_article'.format(field_name)
            ):
                ret.pop(field_name)  #  remove field if it's not permitted

        return ret

    def to_internal_value(self, request_data):
        errors = {}
        # get the original representation
        ret = super(ArticleSerializer, self).to_internal_value(request_data)
        current_user = self.context['request'].user
        for field_name, field_value in sorted(ret.items()):
            if field_value and not current_user.has_perm(
                'app_name.change_{}_article'.format(field_name)
            ):
                errors[field_name] = ["Field not allowed to change"]  # throw error if it's not permitted

        if errors:
            raise ValidationError(errors)

        return ret
Run Code Online (Sandbox Code Playgroud)


rav*_*shi 5

我想出了办法.在序列化程序中,我可以访问对象和发出API请求的用户.因此,我可以检查请求者是否是对象的所有者并返回私人信息.如果不是,序列化程序将返回一个空字符串.

class UserInfoSerializer(serializers.HyperlinkedModelSerializer):
    private_field1 = serializers.SerializerMethodField('get_private_field1')

    class Meta:
        model = UserInfo
        fields = (
            'id',
            'public_field1',
            'public_field2',
            'private_field1',
        )
        read_only_fields = ('id')

    def get_private_field1(self, obj):
        # obj.created_by is the foreign key to the user model
        if obj.created_by != self.context['request'].user:
            return ""
        else:
            return obj.private_field1
Run Code Online (Sandbox Code Playgroud)

  • 有关允许读写的解决方案,请参阅 http://stackoverflow.com/a/32302088/3461355 (2认同)