【问题标题】:Get n number of random records using nested serializers Django REST framework使用嵌套序列化程序 Django REST 框架获取 n 条随机记录
【发布时间】:2021-08-10 16:04:41
【问题描述】:

我正在尝试从外键相关模型中获取随机“n”条记录。假设我有两个名为 ExamQuestions 的模型。我需要一个 API 端点来获取一个特定主题的 n 个问题(例如数学,n 个随机数学问题)。端点在检索特定主题的所有问题方面运行良好。

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'

查看文档后,我尝试使用to_representation() 方法过滤并获取随机记录,但失败了。非常感谢任何帮助。

【问题讨论】:

  • queryset = Exam.objects.all('?') 并且您可以使用分页仅选择 n 项目。
  • @WillemVanOnsem 是的,我也有这个想法 :) 但它可以暴露所有问题。
  • 这就是分页的内容,或者您​​可以通过覆盖get_queryset 方法来限制它。
  • 对于问题模型...必须调查一下:)

标签: django django-models django-rest-framework django-serializer


【解决方案1】:

如果您想要 1 次考试的 N 个随机问题,我会执行以下操作:

  • 在 Viewset(或自定义视图)中创建自定义操作
    • 应该是一个DETAIL模型动作,意思是看起来像exams/3/your-action-name/
    • 应该是GET请求
  • 然后实现如下逻辑:
    • 获取考试模型
    • 然后使用 "?" 获取该考试的问题,以随机排序并且只需要几个
    • 然后序列化问题实例
    • 并返回数据

它可能是这样的:

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)

【讨论】:

    【解决方案2】:

    终于找到了不改变实现的方法,之前尝试使用to_representation()是在错误的序列化器中完成的。无论如何,可以使用np.random.choice() 返回“n”个随机记录,这就是我的做法。在Question序列化器中,

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation['questions'] = np.random.choice(
             representation['questions'],
             10, # n(=10) number of records
             replace=False
        )
    
        return representation
    

    但是,使用to_representation() 意味着将加载所有问题对象,然后从该列表中,np.random.choice() 将获得 n 条随机记录。这不是很酷。


    所以看来 @Jordan 答案更方便,所以我使用 APIView 而不是 generics.RetrieveAPIView 并且没有使用嵌套序列化。

    class ExamQuestionAPIView(APIView):
    
        def get_object(self, name):
            try:
                return Quiz.objects.get(name=name)
            except Quiz.DoesNotExist:
                raise Http404
    
        def get(self, request, name, format=None):
            """
                Return 10 random questions.
            """
    
            questions = QuizQuestion.objects.filter(
                quiz=self.get_object(name)
            ).order_by('?')[:10]
    
            questions_serialized = QuizQuestionSerializer(questions, many=True)
    
            return Response(questions_serialized.data)
    

    【讨论】:

      猜你喜欢
      • 2021-06-23
      • 2019-12-23
      • 2016-05-14
      • 2018-12-13
      • 2015-02-17
      • 2020-07-07
      • 2014-07-27
      • 2015-08-14
      相关资源
      最近更新 更多