Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ami/main/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ def get_queryset(self) -> QuerySet:
queryset = queryset.select_related(
"event",
"deployment",
"deployment__data_source",
).order_by("timestamp")

if self.action == "list":
Expand Down
28 changes: 28 additions & 0 deletions ami/main/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3206,6 +3206,34 @@ def test_list_query_with_counts_and_detections(self):
)
self.assertLessEqual(large, small + 5, f"SourceImage list scaling: {small} -> {large} (likely N+1)")

def test_list_response_shape_has_no_lazy_loads(self):
"""Every row must serialize `url`, `size_display`, `deployment.name`, and
`event.name` without lazy loads — `select_related("deployment__data_source")`
is the contract that prevents per-row queries from `SourceImage.public_url()`."""
from django.core.cache import caches
from django.test.utils import CaptureQueriesContext

url = f"/api/v2/captures/?project_id={self.project.pk}&limit=5"
self.client.get(url)
caches["default"].clear()
with CaptureQueriesContext(connection) as ctx:
res = self.client.get(url)
self.assertEqual(res.status_code, status.HTTP_200_OK)
body = res.json()
self.assertGreater(len(body["results"]), 0)
row = body["results"][0]
# Confirm fields the serializer reads (some via model methods) are non-null/present.
for key in ("id", "url", "size_display", "deployment", "event", "detections_count", "path"):
self.assertIn(key, row, f"missing field {key!r} in list response")
self.assertIsNotNone(row["deployment"]["name"])
# No lazy-load queries should fire after the main list SELECT.
# 1 list select + 1 detection prefetch (no, not in this call) + savepoints.
self.assertLessEqual(
len(ctx.captured_queries),
6,
f"Unexpected extra queries — likely lazy-load from deferred field: {len(ctx.captured_queries)}",
)


@override_settings(CACHALOT_ENABLED=False)
class TestTaxonListQueryCount(APITestCase):
Expand Down
Loading