Files
SportstimeAPI/core/admin/stadium_admin.py
Trey t 63acf7accb feat: add Django web app, CloudKit sync, dashboard, and game_datetime_utc export
Adds the full Django application layer on top of sportstime_parser:
- core: Sport, Team, Stadium, Game models with aliases and league structure
- scraper: orchestration engine, adapter, job management, Celery tasks
- cloudkit: CloudKit sync client, sync state tracking, sync jobs
- dashboard: staff dashboard for monitoring scrapers, sync, review queue
- notifications: email reports for scrape/sync results
- Docker setup for deployment (Dockerfile, docker-compose, entrypoint)

Game exports now use game_datetime_utc (ISO 8601 UTC) instead of
venue-local date+time strings, matching the canonical format used
by the iOS app.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 14:04:27 -06:00

90 lines
2.7 KiB
Python

from django.contrib import admin
from django.utils.html import format_html
from import_export.admin import ImportExportMixin
from simple_history.admin import SimpleHistoryAdmin
from core.models import Stadium, StadiumAlias
from core.resources import StadiumResource
class StadiumAliasInline(admin.TabularInline):
model = StadiumAlias
extra = 0
fields = ['alias', 'alias_type', 'valid_from', 'valid_until', 'is_primary']
ordering = ['-valid_from']
@admin.register(Stadium)
class StadiumAdmin(ImportExportMixin, SimpleHistoryAdmin):
resource_class = StadiumResource
list_display = [
'name',
'sport',
'location_display',
'capacity_display',
'surface',
'roof_type',
'opened_year',
'home_team_count',
'alias_count',
]
list_filter = ['sport', 'country', 'surface', 'roof_type']
search_fields = ['id', 'name', 'city', 'state']
ordering = ['sport', 'city', 'name']
readonly_fields = ['id', 'created_at', 'updated_at', 'map_link']
inlines = [StadiumAliasInline]
fieldsets = [
(None, {
'fields': ['id', 'sport', 'name']
}),
('Location', {
'fields': ['city', 'state', 'country', 'timezone']
}),
('Coordinates', {
'fields': ['latitude', 'longitude', 'map_link']
}),
('Venue Details', {
'fields': ['capacity', 'surface', 'roof_type', 'opened_year']
}),
('Media', {
'fields': ['image_url']
}),
('Metadata', {
'fields': ['created_at', 'updated_at'],
'classes': ['collapse']
}),
]
def location_display(self, obj):
return obj.location
location_display.short_description = 'Location'
def capacity_display(self, obj):
if obj.capacity:
return f"{obj.capacity:,}"
return '-'
capacity_display.short_description = 'Capacity'
def home_team_count(self, obj):
return obj.home_teams.count()
home_team_count.short_description = 'Teams'
def alias_count(self, obj):
return obj.aliases.count()
alias_count.short_description = 'Aliases'
def map_link(self, obj):
if obj.latitude and obj.longitude:
return format_html(
'<a href="https://www.google.com/maps?q={},{}" target="_blank">View on Google Maps</a>',
obj.latitude, obj.longitude
)
return '-'
map_link.short_description = 'Map'
def get_search_results(self, request, queryset, search_term):
"""Enable autocomplete search."""
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
return queryset, use_distinct