Получение количества связанных элементов и вычитание его из атрибута в django
У меня три модели, и я пытаюсь немного упростить свои запросы.
Я пытаюсь вернуть список Course объектов, которые не были полностью зарегистрированы/оплачены. Поэтому мне нужно получить количество Payment объектов, а затем посмотреть, равно ли оно общему количеству available_seats на Course объекте.
У меня есть Payment, Course и Registration модели:
class Payment(models.Model):
payment = models.ForeignKey(Payment, on_delete=models.PROTECT)
registration = models.ForeignKey(Registration, on_delete=models.PROTECT)
is_refunded = models.BooleanField(default=False)
class Course(models.Model):
course = models.ForeignKey(Course, on_delete=models.PROTECT)
location = models.ForeignKey(Location, on_delete=models.PROTECT)
seat_count = models.IntegerField()
class Registration(models.Model):
person = models.ForeignKey(Person, on_delete=models.PROTECT)
course = models.ForeignKey(Course, on_delete=models.PROTECT)
comments = models.CharField(max_length=200, blank=True, null=True)
Я хочу считать место "занятым", только если было сделано Payment - поэтому подсчет Payment для данного Course - это то, что я пытаюсь получить.
Я пытался сделать что-то вроде этого:
payments = (
Payment.objects.filter(
registration__course__id=OuterRef("pk"), is_refunded=False
).values("pk")
# .annotate(
# total_seats_available=F("registration__course__seat_count")
# - Count("registration")
# )
# .values("total_seats_available")
)
courses = (
Course.objects.filter(id__in=course_ids)
.prefetch_related(
Prefetch(
"registration_set",
queryset=Registration.objects.prefetch_related(
"payment_set"
),
)
)
.annotate(
paid_seats=Case(
When(
Exists(payments),
then=Count(payments),
),
default=None,
),
has_available_seats=Case(
# No Payment have been recorded
When(paid_seats=None, then=Value(True)),
# Payment exist and total_seats_available should calc
When(paid_seats__gt=0, then=Value(True)),
# Default to False
default=Value(False),
output_field=BooleanField(),
),
)
.filter(has_available_seats=True)
)
В настоящее время это возвращает счетчик объектов Payment и если он больше 0, то считается, что курс имеет свободные места.
Каким образом лучше всего выполнить логику, чтобы Course аннотировал значение, которое является seat_count - payments для получения точного представления о том, "сколько" мест действительно доступно?
Где должна находиться эта логика? Я оставил некоторую логику, которую я закомментировал и которая не работала. Я не могу понять, как это сделать правильно.
Я смог заставить это работать с помощью F() выражений:
payments = (
Payment.objects.filter(
registration__course__id=OuterRef("pk"), is_refunded=False
).values("pk")
)
courses = (
Course.objects.filter(id__in=course_ids)
.prefetch_related(
Prefetch(
"registration_set",
queryset=Registration.objects.prefetch_related(
"payment_set"
),
)
)
.annotate(
paid_seats=Case(
When(
Exists(payments),
then=Count(payments),
),
default=None,
),
available_seats=Case(
When(Exists(payments), then=F('seat_count')-F('paid_seats'),
default=F('seat_count'),
output_field=IntegerField(),
),
has_available_seats=Case(
When(available_seats__gte=0, then=Value(True)),
default=Value(False),
output_field=BooleanField(),
),
)
.filter(has_available_seats=True)
)