Consider the following scenario (models)
class Service(models.Model):
service_type = models.ForeignKey(
ServiceType,
related_name="typeservices"
on_delete=models.CASCADE,
)
description = models.TextField()
active = models.BooleanField(default=True)
class Booking(models.Model)
service = models.ForeignKey(
Service,
related_name="bookings"
on_delete=models.CASCADE,
)
category = models.CharField(max_length=255)
price = models.IntegerField()
client_serial = models.CharField(max_length=255)
class Client(models.Model):
serial = models.CharField(max_length=255, unique=True)
Now I have a queryset of services. I would like to decorate (annotate) the queryset with extra columns representing the number of times services were booked – I would like that to happen for bookings of specific price
and serial_serial
. I anticipate that only one item will satisfy the query at most. So I did …
queryset.annotate(
# number of occurrence
occurs=models.Count(
"bookings",
filter=models.Q(
bookings__client_serial='1234ARG-QWE',
bookings__price=45.00
)
)
)
That works.
Count()
returns a single value (an aggregation). It suited the annotation since I wanted a unit value for the booking made by a specific client
, for $45
– something that should happen only once. But I also want two more annotations on the queryset from Bookings. So I append the following to the above query …
.annotate(
# booking category
cat=models.F("bookings__category")
).annotate(
booking_id=models.F("bookings__pk")
)
My observation is that I get duplicate entries. It pulls services that were not booked and decorates them. Without the last annotate()
block, everything is fine. Why? How do I build this query such that the queryset does not grow to include irrelevant entries?