1
\$\begingroup\$

my models

class AssessmentTest(BasicModel):
    title = models.CharField(max_length=120, unique=True)


class UserTestResult(BasicModel):
    assessment_test = models.ForeignKey(AssessmentTest, on_delete=models.CASCADE, related_name='users_passed')
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='test_results')
    points = models.PositiveIntegerField(default=0)

my views

class AssessmentTestView(ReadOnlyModelViewSet):
    serializer_class = AssessmentTestSerializer
    queryset = AssessmentTest.objects.all()

my serializers

class AssessmentTestListSerializer(serializers.ModelSerializer):
    class Meta:
        model = AssessmentTest
        fields = [
            'id',
            'title',
            'user_results',
        ]

    user_results = serializers.SerializerMethodField()

    def get_user_results(self, obj: AssessmentTest):
        user = self.context['request'].user
        if not user.is_anonymous:
            test_result = UserTestResult.objects.filter(assessment_test=obj, user=user)
            if test_result:
                return UserTestResultSerializer(instance=test_result.last()).data
        return None

When I try to get all tests, in get_user_results I face n+1 problem (for every test there is extra query to UserTestResult)

Can I somehow avoid this? Maybe it's possible to use prefetch_related on reverse foreign_key in queryset? Or not? Can someone help?

\$\endgroup\$
2
  • \$\begingroup\$ Looks like that should be a nested serialiser to me - you're embedding the results for UserTest in AssessmentTest. Take a look at the docs on the subject if you wish. \$\endgroup\$ Nov 8, 2021 at 14:32
  • \$\begingroup\$ Is this piece of code working as intended to the best of your knowledge ? If not, it is off-topic here and Stackoverflow would be the place to post this. Then some more context would be welcome ie showing a data sample that illustrates the problem, and the expect result. \$\endgroup\$
    – Kate
    Nov 8, 2021 at 23:49

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.