使用嵌套序列化器 Django REST 框架获取 n 条随机记录
Get n number of random records using nested serializers Django REST framework
我正在尝试从外键相关模型中随机获取 'n' 条记录。假设我有两个名为 Exam
和 Questions
的模型。我需要一个 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()
方法过滤并获取随机记录,但失败了。非常感谢任何帮助。
如果你想要 1 次考试的 N 个随机问题,我会执行以下操作:
- 在视图集中创建自定义操作(或自定义视图)
- 它应该是一个 DETAIL 模型动作,意思是它看起来像
exams/3/your-action-name/
- 应该是GET请求
- 然后实现如下逻辑:
- 获取考试模型
- 然后使用
"?"
获取该考试的问题,随机排序,只取一些
- 然后序列化问题实例
- 和return数据
它可能是这样的:
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)
终于找到了不改变实现的方法,之前尝试使用to_representation()
是在错误的序列化器中完成的。无论如何,我可以使用 np.random.choice()
return '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)
我正在尝试从外键相关模型中随机获取 'n' 条记录。假设我有两个名为 Exam
和 Questions
的模型。我需要一个 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()
方法过滤并获取随机记录,但失败了。非常感谢任何帮助。
如果你想要 1 次考试的 N 个随机问题,我会执行以下操作:
- 在视图集中创建自定义操作(或自定义视图)
- 它应该是一个 DETAIL 模型动作,意思是它看起来像
exams/3/your-action-name/
- 应该是GET请求
- 它应该是一个 DETAIL 模型动作,意思是它看起来像
- 然后实现如下逻辑:
- 获取考试模型
- 然后使用
"?"
获取该考试的问题,随机排序,只取一些 - 然后序列化问题实例
- 和return数据
它可能是这样的:
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)
终于找到了不改变实现的方法,之前尝试使用to_representation()
是在错误的序列化器中完成的。无论如何,我可以使用 np.random.choice()
return '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)