Home > Software engineering >  annotate is adding an extra object to my queryset
annotate is adding an extra object to my queryset

Time:12-31

I'm using DRF. I've got the following code where I annotate a queryset of Company objects with an additional joined field. It seems annotate is adding an extra object to my queryset.

views.py

def get(self, request, **kwargs):
        user = request.user
        
        companies = Company.objects.all()

        print(companies)
        
        user_in_queue = When(queue__users=user, then = True)
        
        companies = Company.objects.annotate(joined=Case(
            user_in_queue, default = False
        ))
        
        print(companies)

models.py

class Company(models.Model):
    name = models.CharField(max_length=15, unique=True)

    def __str__(self) -> str:
        return self.name
    
class User(AbstractUser):
    def __str__(self) -> str:
        return f"{self.username}"


class Queue(models.Model):
    company = models.OneToOneField(
        Company, on_delete=models.CASCADE, related_name="queue"
    )
    users = models.ManyToManyField(User, through="QueueDetails", related_name="queues")

class QueueDetails(models.Model):
    
    queue = models.ForeignKey(
        Queue,
        related_name="queue_details",
        on_delete=models.CASCADE,
    )
    user = models.ForeignKey(
        User,
        related_name="queue_details",
        on_delete=models.CASCADE,
    )

the first print gives me

<QuerySet [<Company: kfc>, <Company: kfc>]>

With a json of

[
    {
        "name": "kfc",
        "id": 1,
    },
    {
        "name": "kfc",
        "id": 2,
    }
]

The second gives me

<QuerySet [<Company: kfc>, <Company: kfc>, <Company: kfc>]>

With a json of

[
    {
        "name": "kfc",
        "id": 1,
        "joined": null
    },
    {
        "name": "kfc",
        "id": 1,
        "joined": true
    },
    {
        "name": "kfc",
        "id": 2,
        "joined": null
    }
]

I want a json of

[
    {
        "name": "kfc",
        "id": 1,
        "joined": true
    },
    {
        "name": "kfc",
        "id": 2,
        "joined": null
    }
]

CodePudding user response:

You want to work with an Exists subquery [Django-doc] to prevent joining:

from django.db.models import Exists, OuterRef


def get(self, request, **kwargs):
    user = request.user
    companies = Company.objects.annotate(
        joined=Exists(
            Queue.objects.filter(company_id=OuterRef('pk'), users=request.user)
        )
    )
    # …

For the serializer, you add a joined field:

class CompanySerializer(serializers.ModelSerializer):
    joined = serializers.BooleanField()

    # …
  • Related