Search code examples
djangodjango-modelsdjango-rest-frameworkdjango-serializer

Get n number of random records using nested serializers Django REST framework


I'm trying to get random 'n' number of records from foreign key related models. Suppose I have two models named Exam and Questions. I need an API endpoint to get n number of questions for one particular subject(ex. for math, n random math questions). The endpoint is working well in retrieving all the questions for a particular subject.

models.py

class Exam(models.Model):
   
    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name

class Question(models.Model):
    
    exam = models.ForeignKey(Exam, on_delete=models.CASCADE)
    question = models.CharField(max_length=255)

    def __str__(self):
        return '{} - {}'.format(self.question)

serializers.py

class QuestionSerializer(serializers.ModelSerializer):
    
    questions = serializers.CharField(read_only=True)
    answer = serializers.CharField(read_only=True)

    class Meta:
        model = Question
        fields = '__all__'


class ExamSerializer(serializers.ModelSerializer):
    
    name = serializers.CharField(read_only=True)
    questions = QuestionSerializer(many=True, read_only=True, source='question_set')

    class Meta:
        model = Exam
        fields = '__all__'

api_views.py

class ExamQuestionRetrieveAPIView(generics.RetrieveAPIView):

    authentication_classes = [JWTTokenUserAuthentication]

    serializer_class = ExamSerializer
    queryset = Exam.objects.all()
    lookup_field = 'name'

After going through the doc, I tried to filter and get random records using the to_representation() method but failed. Any help is greatly appreciated.


Solution

  • If you want N random questions of 1 exam, I would do the following:

    • Create a custom action in a Viewset (or a custom view)
      • It should be a DETAIL model action, meaning it looks like exams/3/your-action-name/
      • It should be a GET request
    • Then implement the following logic:
      • Fetch the exam model
      • Then fetch the Questions for that exam using "?" to order them randomly and only take a few
      • Then serialize the question instances
      • And return the data

    Here's what it could look like:

    def get_random_questions(self, request, pk=None):
        exam = self.get_object()
        questions = Question.objects.filter(exam=exam).order_by("?")[:5] # Update with your desired number
        serializer = QuestionSerializer(questions, many=True)
        return Reponse(serializer.data)