Home > Enterprise >  Is there a way to dynamically specify a queryset for nested relationship (nested serializer class) i
Is there a way to dynamically specify a queryset for nested relationship (nested serializer class) i

Time:11-20

Suppose we have two models:

class Chapter(models.Model):
    title = models.CharField(max_length=128)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)


class Post(models.Model):
    title = models.CharField(max_length=128)
    body = models.TextField()
    is_archived = models.BooleanField(default=False)
    chapter = models.ForeignKey(Chapter, on_delete=models.CASCADE)

And default ModelViewSet viewset for Chapter model:

class ChapterViewSet(viewsets.ModelViewSet):
    queryset = Chapter.objects.all()
    serializer_class = ChapterSerializer

The key thing is that ChapterSerializer performs nested serialization using PostSerializer to provide a post_set key in the response.

class PostSerializer(serializers.HyperlinkedModelSerializer):
    detail_url = HyperlinkedIdentityField(view_name='post-detail', read_only=True)

    class Meta:
        fields = ['id', 'title', 'is_archived', 'detail_url']
        model = Post

class ChapterSerializer(serializers.ModelSerializer):
    post_set = PostSerializer(read_only=True, many=True)

    class Meta:
        model = Chapter
        fields = ['id', 'title', 'owner', 'post_set']

The question is how I can dynamically specify a queryset for this nested PostSerializer. For example, when user makes GET request I only want to include the posts that are not archived (is_archived field is set to False) if user, who has done a request, is not an owner of a Chapter (request.user != current_chapter.owner). Is there any way to achive it?

CodePudding user response:

You can use prefetch_related to prefetch the results used by a nested serializer, this prefetch can be filtered by using a Prefetch object and this will then filter the nested results

class ChapterViewSet(viewsets.ModelViewSet):
    queryset = Chapter.objects.all()
    serializer_class = ChapterSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.prefetch_related(
            Prefetch('post_set', queryset=Post.objects.filter(is_archived=False))
        )

In the get_queryset method you will have to perform this prefetching dynamically, the current request can be accessed via self.request

  • Related