Based on the git diff provided, here's a concise and descriptive commit message:

feat: add security event taxonomy and optimize park queryset

- Add comprehensive security_event_types ChoiceGroup with categories for authentication, MFA, password, account, session, and API key events
- Include severity levels, icons, and CSS classes for each event type
- Fix park queryset optimization by using select_related for OneToOne location relationship
- Remove location property fields (latitude/longitude) from values() call as they are not actual DB columns
- Add proper location fields (city, state, country) to values() for map display

This change enhances security event tracking capabilities and resolves a queryset optimization issue where property decorators were incorrectly used in values() queries.
This commit is contained in:
pacnpal
2026-01-10 16:41:31 -05:00
parent 96df23242e
commit 2b66814d82
26 changed files with 2055 additions and 112 deletions

View File

@@ -59,7 +59,7 @@ class ParkQuerySet(StatusQuerySet, ReviewableQuerySet, LocationQuerySet):
"reviews",
queryset=ParkReview.objects.select_related("user")
.filter(is_published=True)
.order_by("-created_at")[:10],
.order_by("-created_at"),
),
"photos",
)
@@ -86,7 +86,8 @@ class ParkQuerySet(StatusQuerySet, ReviewableQuerySet, LocationQuerySet):
def for_map_display(self, *, bounds=None):
"""Optimize for map display with minimal data."""
queryset = self.select_related("operator").prefetch_related("location")
# Use select_related for OneToOne relationship to enable values() access
queryset = self.select_related("operator", "location")
if bounds:
queryset = queryset.within_bounds(
@@ -96,13 +97,15 @@ class ParkQuerySet(StatusQuerySet, ReviewableQuerySet, LocationQuerySet):
west=bounds.west,
)
# Note: location__latitude and location__longitude are @property
# decorators, not actual DB fields. We access city/state/country which
# are actual columns. For coordinates, callers should use the point field
# or access the location object directly.
return queryset.values(
"id",
"name",
"slug",
"status",
"location__latitude",
"location__longitude",
"location__city",
"location__state",
"location__country",
@@ -152,6 +155,10 @@ class ParkManager(StatusManager, ReviewableManager, LocationManager):
"""Always prefetch location for park queries."""
return self.get_queryset().with_location()
def search_autocomplete(self, *, query: str, limit: int = 10):
"""Optimized search for autocomplete."""
return self.get_queryset().search_autocomplete(query=query, limit=limit)
class ParkAreaQuerySet(BaseQuerySet):
"""QuerySet for ParkArea model."""
@@ -284,25 +291,10 @@ class CompanyManager(BaseManager):
def major_operators(self, *, min_parks: int = 5):
return self.get_queryset().major_operators(min_parks=min_parks)
def manufacturers_with_ride_count(self):
"""Get manufacturers with ride count annotation for list views."""
return (
self.get_queryset()
.manufacturers()
.annotate(ride_count=Count("manufactured_rides", distinct=True))
.only("id", "name", "slug", "roles", "description")
.order_by("name")
)
def designers_with_ride_count(self):
"""Get designers with ride count annotation for list views."""
return (
self.get_queryset()
.filter(roles__contains=["DESIGNER"])
.annotate(ride_count=Count("designed_rides", distinct=True))
.only("id", "name", "slug", "roles", "description")
.order_by("name")
)
# NOTE: manufacturers_with_ride_count and designers_with_ride_count were removed
# because parks.Company doesn't have manufactured_rides/designed_rides relations.
# Those relations exist on rides.Company, a separate model.
# Use the rides app's company manager for ride-related company queries.
def operators_with_park_count(self):
"""Get operators with park count annotation for list views."""