diff --git a/graphene_linked_events/schema.py b/graphene_linked_events/schema.py index c6c90ec0..79a4fe22 100644 --- a/graphene_linked_events/schema.py +++ b/graphene_linked_events/schema.py @@ -466,8 +466,10 @@ def _test_events_p_event_relations(events_json): events = json.loads(events_json, object_hook=lambda d: SimpleNamespace(**d)) # Get related palvelutarjotin events - p_events = PalvelutarjotinEvent.objects.prefetch_related("occurrences").filter( - linked_event_id__in=[e.id for e in events.data] + p_events = ( + PalvelutarjotinEvent.objects.select_related("organisation") + .prefetch_related("occurrences") + .filter(linked_event_id__in=[e.id for e in events.data]) ) # Prune a list of events which have a link to a palvelutarjotin event diff --git a/occurrences/models.py b/occurrences/models.py index ba71c331..e2879998 100644 --- a/occurrences/models.py +++ b/occurrences/models.py @@ -304,17 +304,25 @@ def has_space_for_enrolments(self) -> Optional[bool]: if not self.has_enrolments_system() or self.has_external_enrolments_system(): return None - has_upcoming_space = any( - occurrence.has_space_left() - for occurrence in self.occurrences.filter_upcoming() - ) + now = timezone.now() + # Use prefetched occurrences (.all()) to avoid extra DB queries per event. + all_occurrences = list(self.occurrences.all()) + + upcoming = [ + o + for o in all_occurrences + if not o.cancelled and o.start_time >= now + ] + has_upcoming_space = any(o.has_space_left() for o in upcoming) if self.enrolment_end_days is None: # No limit to when enrolments can be made before the occurrence start. - return has_upcoming_space or any( - occurrence.has_space_left() - for occurrence in self.occurrences.filter_ongoing() - ) + ongoing = [ + o + for o in all_occurrences + if not o.cancelled and o.start_time <= now and o.end_time >= now + ] + return has_upcoming_space or any(o.has_space_left() for o in ongoing) return has_upcoming_space diff --git a/occurrences/schema.py b/occurrences/schema.py index a288e0f6..81959644 100644 --- a/occurrences/schema.py +++ b/occurrences/schema.py @@ -161,7 +161,13 @@ class Meta: @classmethod def get_queryset(cls, queryset, info): - return super().get_queryset(queryset, info).order_by("start_time") + return ( + super() + .get_queryset(queryset, info) + .select_related("p_event") + .prefetch_related("languages") + .order_by("start_time") + ) def resolve_remaining_seats(self, info, **kwargs): return self.amount_of_seats - self.seats_taken @@ -200,22 +206,23 @@ class Meta: interfaces = (graphene.relay.Node,) def resolve_next_occurrence_datetime(self, info, **kwargs): - try: - return ( - self.occurrences.filter(start_time__gte=timezone.now(), cancelled=False) - .earliest("start_time") - .start_time - ) - except Occurrence.DoesNotExist: + # Filter the prefetched occurrences in Python to avoid extra DB queries. + now = timezone.now() + upcoming = [ + o + for o in self.occurrences.all() + if not o.cancelled and o.start_time >= now + ] + if not upcoming: return None + return min(upcoming, key=lambda o: o.start_time).start_time def resolve_last_occurrence_datetime(self, info, **kwargs): - try: - return ( - self.occurrences.filter(cancelled=False).latest("start_time").start_time - ) - except Occurrence.DoesNotExist: + # Filter the prefetched occurrences in Python to avoid extra DB queries. + non_cancelled = [o for o in self.occurrences.all() if not o.cancelled] + if not non_cancelled: return None + return max(non_cancelled, key=lambda o: o.start_time).start_time def resolve_has_space_for_enrolments(self, info, **kwargs): """ @@ -298,7 +305,7 @@ class Meta: @classmethod def get_queryset(cls, queryset, info): lang = get_language() - return queryset.language(lang) + return queryset.language(lang).prefetch_related("translations") class ExternalPlace(graphene.ObjectType):