0

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

Ryan
  • 77
  • 1
  • 7
  • This has no effect on *filtering*. Likely this is due to the *serializer* serializing relations. Share the `LeadSerializer`. – Willem Van Onsem Aug 09 '22 at 13:25
  • serializer is added – Ryan Aug 09 '22 at 13:43
  • Try adding `User` to `select_related`. It seems that additional queries are coming from `core_user` – Bartosz Stasiak Aug 09 '22 at 14:22
  • @BartoszStasiak Yes, I realized that. It's because of request.user that get authenticated user from the User model. but I don't know how to preload it in the view. I can't do select_related('user) – Ryan Aug 09 '22 at 14:31

1 Answers1

0

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
Ryan
  • 77
  • 1
  • 7