Filter django queryset by its related field

I have a DRF QuesionSet View inherited from generics.RetrieveUpdateDestroyAPIView

I also have 2 models (simplified):

class Question(models.Model):
    question_set = models.ForeignKey(QuestionSet, related_name="questions")
    is_archived = models.BooleanField(default=False)
    ...other_fields

class QuestionSet(models.Model):

    ...fields

Now I need to return a question_set object in the view, that only has questions that are True. Something like this:

"id": 1,
"questions": [
        {
            "id": 1,
            "isArchived": true
        },
        {
            "id": 1,
            "isArchived": true
        },
        {
            "id": 1,
            "isArchived": true
        },
]

I am trying to override get_object() method in the view to return these values. So how do I achieve that?

Upvotes: 0

Views: 1327

Answers (3)

I was able to solve it by overriding qs:

return self.queryset.prefetch_related(Prefetch('questions', 
                               queryset=Question.objects.filter(is_archived=True)))

Upvotes: 1

Michael Haar
Michael Haar

Reputation: 711

It turned out to be trickier than I thought. I suggest to use a SerializerMethodField.

#content of serializers.py

from rest_framework import serializers
from .models import Question, QuestionSet


class QuestionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Question
        fields = ['id', 'is_archived', 'question_set']


class QuestionSetSerializer(serializers.ModelSerializer):
    inactive_questions = serializers.SerializerMethodField()

    class Meta:
        model = QuestionSet
        fields = ['id', 'inactive_questions']

    def get_inactive_questions(self, obj):
        active_questions = obj.questions.filter(is_archived=True)
        return QuestionSerializer(active_questions, many=True, read_only=True).data

More details can be find in the Github repo

Upvotes: 2

Michael Haar
Michael Haar

Reputation: 711

First, you can overwrite the get_queryset method to filter the queryset:

def get_queryset(self):
    return QuestionSet.objects.select_related('questions').filter(is_archived=True)

Next you have to modify the serializer class in order to get the required output format. Try using nested serializers:

class QuestionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Question
        fields = ['id', 'is_archived']

class QuestionSetSerializer(serializers.ModelSerializer):
    questions = QuestionSerializer(many=True, read_only=True)

    class Meta:
        model = QuestionSet
        fields = ['id']

Upvotes: 1

Related Questions