⚡ Stop the events homepage from running a query per event - #3136
jefftriplett wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
There are a few correctness/performance issues in the updated code paths (notably an incorrect return annotation and a potential performance regression when recurring_rules is not prefetched) that should be addressed before merging.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 2
Open (3)
What changed in this PR
Reduces database query volume on the /events/ homepage by ensuring the list view eagerly loads related event data and by making Event.next_time / Event.previous_time able to reuse prefetched recurring_rules rather than triggering per-event queries during template rendering.
Changes:
- Add a
with_related()helper onEventHomepageand applyselect_related(...)/prefetch_related(...)to the homepage querysets. - Update
Event.next_time/Event.previous_timeto filterrecurring_rulesin Python so the prefetch cache can be reused. - Add a regression test asserting homepage query count does not grow as more events are added.
| File | Description |
|---|---|
| apps/events/views.py | Centralizes related-object eager loading for the events homepage and reuses a single now timestamp across homepage queries/sorts. |
| apps/events/models.py | Adjusts next_time / previous_time to avoid bypassing prefetched recurring_rules cache. |
| apps/events/tests/test_views.py | Adds a query-count regression test to guard against future N+1 regressions on /events/. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The changes directly address the N+1 query behavior with consistent eager-loading and include a regression test guarding against query-per-row regressions.
Review effort: Lite
Findings: None
Resolved since last review (3)
6f9d3f5 to
e4407b4
Compare


/events/runs a query for every event on the page.EventHomepageloads all past and all upcoming events into Python lists, and the list template then readsnext_time,is_scheduled_to_start_this_year,is_scheduled_to_end_this_year,venueandget_absolute_urlfor each row, and every one of those hits the database.Two changes:
select_related("occurring_rule", "venue", "calendar")andprefetch_related("recurring_rules").Event.next_time/Event.previous_timefilter the prefetchedrecurring_rulesin Python. They called.filter()on the related manager, which bypasses the prefetch cache and so queried once per event.GET
/events/, locally against Postgres:Fixes #3125