djangodjango-modelsdjango-rest-frameworkdjango-viewsdjango-select-related

Django select_related doesn't optimize query


I have a problem with select_related. I don't know what I'm doing wrong but it doesn't work..

models.py

class OrganizerUser(models.Model):
    """This user manage Agents"""
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.user.username


class Agent(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    organizer = models.ForeignKey(OrganizerUser, blank=True, null=True,
                                  on_delete=models.CASCADE)

    def __str__(self):
        return self.user.username



class Lead(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    age = models.IntegerField(default=0)
    organizer = models.ForeignKey(OrganizerUser, on_delete=models.CASCADE)
    agent = models.ForeignKey(Agent, null=True, blank=True, on_delete=models.SET_NULL)
   
    category = models.ForeignKey(
        Category, related_name="categories", null=True, blank=True,  on_delete=models.SET_NULL
    )
    description = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)
    phone_number = models.CharField(max_length=20)
    email = models.EmailField()
    converted_date = models.DateTimeField(null=True, blank=True)

    def __str__(self):
        return f"{self.first_name} {self.last_name}"

views.py

class LeadsApiView(generics.ListCreateAPIView):
    serializer_class = LeadSerializer
    permission_classes = [IsAuthenticated, IsAdminOrOrganizer]

    def get_queryset(self):
        user = self.request.user
        #if user.is_staff:
            #return Lead.objects.select_related('organizer', 'agent').all()
        if user.is_organizer:
            return Lead.objects.select_related('organizer').filter(
                organizer=user.organizeruser)
        else:
            return Lead.objects.select_related('agent').filter(agent=user.agent)

serializers.py

class LeadSerializer(serializers.ModelSerializer):
    class Meta:
        model = Lead
        fields = ['id', 'first_name', 'last_name', 'age',
                  'organizer', 'agent', 'category', 'description', 'date_added',
                  'phone_number', 'email', 'converted_date'
                  ]

for agents everything is fine. Django makes 3 queries but for other users, it makes extra queries for each existing user.

enter image description here


Solution

  • This solution solved the problem How to always prefetch_related for a specific django model

    class UsersManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().select_related('user')
    
    
    class OrganizerUser(models.Model):
        """This user manage Agents"""
        user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    
        objects = UsersManager()
    
        def __str__(self):
            return self.user.username
    
    
    class Agent(models.Model):
        user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    
        organizer = models.ForeignKey(OrganizerUser, blank=True, null=True,
                                      on_delete=models.CASCADE)
        objects = UsersManager()
    
        def __str__(self):
            return self.user.username