11from django .db import transaction
22from custom_admin .admin import validate_single_conference_selection
33from import_export .resources import ModelResource
4- from django .db .models import Prefetch
4+ from django .db .models import Count , Prefetch
55from typing import Dict
66from django import forms
77from django .contrib import admin , messages
@@ -317,6 +317,7 @@ class ScheduleItemAdmin(ConferencePermissionMixin, admin.ModelAdmin):
317317 "talk_manager" ,
318318 "type" ,
319319 "submission" ,
320+ "attendees_count" ,
320321 )
321322 list_filter = ("conference" , "status" , "type" )
322323 ordering = ("conference" , "slot" )
@@ -399,7 +400,12 @@ class ScheduleItemAdmin(ConferencePermissionMixin, admin.ModelAdmin):
399400 )
400401
401402 def get_queryset (self , request ):
402- return super ().get_queryset (request ).prefetch_related ("rooms" )
403+ return (
404+ super ()
405+ .get_queryset (request )
406+ .prefetch_related ("rooms" )
407+ .annotate (attendees_count_annotation = Count ("attendees" , distinct = True ))
408+ )
403409
404410 def get_urls (self ):
405411 return [
@@ -484,11 +490,11 @@ def email_speakers(self, request):
484490
485491 return TemplateResponse (request , "email-speakers.html" , context )
486492
487- def spaces_left (self , obj ) :
493+ def spaces_left (self , obj : ScheduleItem ) -> int | None :
488494 if obj .actual_attendees_total_capacity is None :
489495 return None
490496
491- return obj .actual_attendees_total_capacity - obj .attendees . count ()
497+ return obj .actual_attendees_total_capacity - obj .attendees_count_annotation
492498
493499 def save_form (self , request , form , change ):
494500 if form .cleaned_data ["new_slot" ]:
@@ -503,10 +509,18 @@ def save_form(self, request, form, change):
503509
504510 return return_value
505511
506- def speakers_names (self , obj ) :
512+ def speakers_names (self , obj : ScheduleItem ) -> str :
507513 return ", " .join ([speaker .display_name for speaker in obj .speakers ])
508514
509- def invitation_link (self , obj ):
515+ @admin .display (description = "Attendees" )
516+ def attendees_count (self , obj : ScheduleItem ) -> str :
517+ count = obj .attendees_count_annotation
518+ capacity = obj .actual_attendees_total_capacity
519+ if capacity is None :
520+ return str (count )
521+ return f"{ count } / { capacity } "
522+
523+ def invitation_link (self , obj : ScheduleItem ) -> str :
510524 return f"https://pycon.it/schedule/invitation/{ obj .submission .hashid } "
511525
512526
0 commit comments