Создание аннотации на основе подзапроса с параметрами

В моем приложении есть две модели, Event и Registration, с наиболее важными полями ниже:

class Event(models.Model):
    ...
    capacity = models.IntegerField()
    ...
class Registration(models.Model):
    timestamp = models.DateTimeField(auto_now_add=True)
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    uses_bus = models.BooleanField(default=False)
    is_vegan = models.BooleanField(default=False)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        default=None)

Теперь, либо в поле, либо в админке, я пытаюсь получить количество регистраций, где пользователь отметил uses_bus и количество регистраций, где пользователь отметил is_vegan. Это может быть что-то вроде этого:

class EventAdmin(admin.ModelAdmin):
    list_display = ('title', 'date', 'nr_registrations', 'nr_bus')
    inlines = [RegistrationInline]

    def get_queryset(self, request):
        queryset = super(EventAdmin, self).get_queryset(request)
        return queryset.annotate(
            nr_registrations = Count('registration'),
            nr_bus = Count('registration', filter=Q(registration__uses_bus=True)),
            nr_vegan = Count('registration', filter=Q(registration__is_vegan=True)),
        )

    def nr_registrations(self, obj):
        return obj.nr_registrations
    
    def nr_bus(self, obj):
        return obj.nr_bus
    
    def nr_vegan(self, obj):
        return obj.nr_vegan

но это, очевидно, определяет общее количество регистраций на автобус, а не количество регистраций на автобус для тех, кто действительно может посетить мероприятие из-за ограничений по вместимости.

В SQL я бы решил это следующим образом:

SELECT SUM(uses_bus)
FROM (SELECT CAST(uses_bus AS INTEGER)
     FROM events_registration WHERE event_id = *event id* ORDER BY id LIMIT *capacity*)
AS a

но я не могу этого сделать, потому что даже если бы я использовал RawSQL, я не мог бы использовать F() для передачи идентификатора события и мощности в качестве параметров.

Возможно ли это решить? Я также открыт для расширения моделей, добавления полей и т.д.

BrianD уже сказал, вы можете проверить capacity и calculated no, чтобы получить количество регистраций на автобус для тех, кто действительно может посетить мероприятие из-за ограничений по вместимости.

def nr_bus(self, obj):
    if obj.capacity <= obj.nr_bus:
        return obj.capacity
    return obj.nr_bus
    
def nr_vegan(self, obj):
    if obj.capacity <= obj.nr_vegan:
         return obj.capacity
    return obj.nr_vegan
Вернуться на верх