Prefetching Strategy
This document explains the prefetching methods used to optimize cost calculations and view performance in Gyrinx.
Overview
The cost system relies on proper prefetching to:
Enable the facts system - The
can_use_factsproperty requireswith_latest_actions()Avoid N+1 queries - List and detail views need related data prefetched
Optimize display methods -
cost_display(),rating_display()use cached facts when available
QuerySet Methods
List.objects.with_latest_actions()
Lightweight prefetch that enables the facts system:
def with_latest_actions(self):
"""
Prefetch the latest action for each list.
This enables the facts system by populating the `latest_actions` attribute,
which is checked by the `can_use_facts` property.
"""
return self.prefetch_related(
Prefetch(
"actions",
queryset=ListAction.objects.order_by(
"list_id", "-created", "-id"
).distinct("list_id"),
to_attr="latest_actions",
),
)When to use: Any view that displays list costs (campaigns, homepage, list index).
What it enables:
list.can_use_factsreturnsTruelist.latest_actionreturns the most recent actionlist.facts()can return cached values
List.objects.with_related_data()
Full optimization for list detail pages:
When to use: List detail views, edit views.
Parameters:
with_fighters=False(default): Just list-level datawith_fighters=True: Also prefetch all fighters and their equipment
List.objects.with_fighter_data()
Prefetch fighters with their full related data:
When to use: Combined with with_related_data(with_fighters=True).
ListFighter.objects.with_related_data()
Fighter-level optimization:
When to use: Fighter detail views, lists of fighters.
ListFighterEquipmentAssignment.objects.with_related_data()
Equipment assignment optimization:
When to use: Equipment lists, assignment detail views.
The can_use_facts Property
The facts system is gated by can_use_facts:
Important: If you skip the prefetch, can_use_facts returns False and display methods fall back to direct calculation.
View Patterns
Multi-List Views (Campaigns, Homepage)
Use with_latest_actions() for fast cost display:
List Detail Views
Use with_related_data() for full data:
Fighter Detail Views
Use fighter-level prefetch:
The _prefetched_objects_cache Check
The facts_from_db() method checks for prefetched data to avoid redundant queries:
This means:
If you've already prefetched fighters,
facts_from_db()reuses themIf you haven't, it fetches them with appropriate optimization
Performance Impact
Campaign page (10 lists)
30+ queries
3 queries
List detail page
50+ queries
5-10 queries
Fighter detail page
20+ queries
3-5 queries
Common Mistakes
1. Forgetting with_latest_actions()
2. Not using with_fighters for detail views
3. Double prefetching
See Also
Fighter Cost System Reference - Facts API documentation
Cost Handler Development Guide - Handler patterns
Last updated