简体   繁体   中英

Django Rest Framework: Filter/Validate Related Fields

I have two models: Foo which carries an owner field and Bar which has a relation to 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')
    [...]

I use HyperlinkedModelSerializer for representation:

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')

My views look like this:

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)

I don't whant User A to be able to see User B's stuff and vice versa. That works pretty well so far with one exception:

User A created an instance of Foo but doesn't instantly create an instance of Bar linking to Foo. Now User B can guess the URL to User A's Foo instance and specify that when creating his instance of Bar.

At this point, User A gets an instance of Bar which he didn't create.

I'm new to Django and rest_framework, so I have no idea how to solve this. Can somebody get me on the right track? My first idea was to use the foo field in BarSerializer to filter Foos using the queryset. But I didn't figure out how to get access to the auth.User object from there.

You can access the request inside a Serializer if you include it in its context . Then you can do field level validation inside the Bar serializer:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM