Reputation: 87
I have the following Django models:
class Table(models.Model):
# model fields
@property
def is_finished(self):
return not Meal.objects.filter(table=self)\
.filter(finished_time=None).exists()
class Meal(models.Model):
table = models.ForeignKey(
Table,
null=True,
blank=True,
on_delete=models.CASCADE,
related_name='meals'
)
finished_time = models.DateTimeField(null=True, blank=True, default=None)
A table is considered finished if all meals for it have a finished_time. I would like to annotate is_finished in a queryset, to exclude tables where are meals are finished.
Something like:
Table.objects.all()\
.annotate(has_meals=Count('meals__finished_time'))\
.annotate(finished=Min('meals__finished_time'))\
.filter(finished=None)\
.exclude(has_meals=0)
But this does not work if I have finished meals and unfinished meals on a table. How can I fix this?
Upvotes: 1
Views: 63
Reputation: 13731
I'd use an Exists subquery.
from django.db.models import Exists, OuterRef
Table.objects.all().annotate(
is_finished=~Exists(
Meal.objects.filter(table=OuterRef('id'), finished_time__isnull=True)
)
)
The ~
flips the Exists value. To determine if there are any finished this will look to see if there any unfinished meals left, then flip it.
Upvotes: 1