Elabbasy00
Elabbasy00

Reputation: 678

django Select_related(): from another model has a ForginKey To the model that will execute Select_related

I have two model, one for Question and two for answer

tow have a forginkey to one and one have a forginkey to users

for this purpose I use a To be grouped together at the same endpoint I add the second to the first in serializer

With this solution, Django accessed the database with the number of answers in the second form and I cannot use Select_related here

the question is, how can I reduce database hits to the second model

Models.py

class Consultation(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    create_at = models.DateTimeField(auto_now_add=True)
    files = models.FileField(upload_to="media/files", null=True, blank=True,
                             validators=[FileExtensionValidator(['pdf', 'jpg', 'png'])])
        
    def __str__(self):
        return self.user.username

    class Meta:
        ordering = ['-create_at']



class ConsultaionAnswer(models.Model):
    consultation = models.ForeignKey(
        Consultation, on_delete=models.CASCADE, related_name='reply')
    answer = models.TextField(null=True, blank=True)

    def __str__(self):
        return self.consultation.content[:20] + "..."

serializers.py

class ConsultaionAnswerSerilaizers(serializers.ModelSerializer):
    class Meta:
        model = ConsultaionAnswer
        fields = ('answer',)


class ConsultationSerilaizers(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(
        read_only=True,
        default=serializers.CurrentUserDefault()
    )
    username = serializers.StringRelatedField(
        source='user.username',
        read_only=True,
    )
    reply = ConsultaionAnswerSerilaizers(read_only=True, many=True)
 

    class Meta:
        model = Consultation
        fields = (
            "id",
            "user",
            "content",
            'create_at',
            'files',
            'username',
            "reply"
        )

views.py

class ConsultationView(APIView):
    serializer_class = ConsultationSerilaizers

    def get(self, request, format=None):
        consultat = Consultation.objects.select_related().filter(user=request.user)
        serializer = self.serializer_class(
            consultat, many=True, context={'request': request})
        return Response(serializer.data)

django debug tool bar enter image description here

Upvotes: 1

Views: 691

Answers (1)

Preeti Y.
Preeti Y.

Reputation: 525

This should works:

consultat = Consultation.objects.prefetch_related('reply').filter(user=request.user)

Since it is a one-to-many relation, you'll need a prefetch_related instead (see this link). And you also need to specify which field(s) you want to prefetch as well.

prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using select_related,

Upvotes: 1

Related Questions