Django Rest框架:过滤/验证相关字段

时间:2016-09-06 06:31:05

标签: python django django-rest-framework

我有两个模型:Foo带有一个所有者字段,而Bar与Foo有关:

class Foo(models.Model):
    owner = models.ForeignKey('auth.User')  
    name = models.CharField(max_length=20, null=True)

class Bar(models.Model):
    foo = models.OneToOneField(Foo, related_name='bar')
    [...]

我使用HyperlinkedModelSerializer进行表示:

class BarSerializer(serializers.HyperlinkedModelSerializer): 
    foo = serializers.HyperlinkedRelatedField(view_name='foo-detail', queryset=Foo.objects.all())
    [...]

    class Meta:
        model = Bar
        fields = ('foo', [...])

class FooSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.SlugRelatedField(read_only=True, slug_field='username')
    bar = serializers.HyperlinkedRelatedField(view_name='bar-detail', read_only=True)

    class Meta:
        model = Foo
        fields = ('name', 'bar', 'owner')

我的观点如下:

class FooViewSet(viewsets.ModelViewSet):
    queryset = Foo.objects.all()
    serializer_class = FooSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwner,)

    def get_queryset(self):
        user = self.request.user

        if not user.is_authenticated():
            return Foo.objects.none()

        if user.username == "admin":
            return Foo.objects.all()

        return Foo.objects.filter(owner=user)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

class BarViewSet(viewsets.ModelViewSet):
    queryset = Bar.objects.all()
    serializer_class = BarSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwner,)

    def get_queryset(self):
        user = self.request.user

        if not user.is_authenticated():
            return Bar.objects.none()

        if user.username == "admin":
            return Bar.objects.all()

        return Bar.objects.filter(foo__owner=user)

我不认为用户A能够看到用户B的内容,反之亦然。到目前为止,这种方法运作良好,只有一个例外:

用户A创建了一个Foo实例,但没有立即创建链接到Foo的Bar实例。现在,用户B可以猜测用户A的Foo实例的URL,并在创建他的Bar实例时指定。

此时,用户A获得了他未创建的Bar实例。

我是Django和rest_framework的新手,所以我不知道如何解决这个问题。有人能让我走上正轨吗?我的第一个想法是使用BarSerializer中的foo字段来使用查询集过滤Foos。但是我没有弄清楚如何从那里访问auth.User对象。

1 个答案:

答案 0 :(得分:1)

如果include it in its context,您可以在序列化程序中访问请求。 然后你可以在Bar序列化器中执行field level validation

def validate_foo(self, val):
    user = self.context['request'].user

    try:
        foo = Foo.objects.get(pk=val)
    except Foo.DoesNotExist:
        raise serializers.ValidationError("Some Error")

    if foo.user is not user:
        raise serializers.ValidationError("Some Error")

   return value