from __future__ import annotations from pathlib import Path from django.conf import settings from django.contrib import admin from django.utils.html import format_html from .models import SiteRun def _artifact_paths(search_id: str) -> list[Path]: media_dir = Path(settings.MEDIA_ROOT) / "sites" return [ media_dir / f"run_{search_id}.json", media_dir / f"sites_{search_id}.png", media_dir / f"demand_{search_id}.png", media_dir / f"competition_{search_id}.png", ] @admin.action(description="Delete selected runs and artifacts") def delete_runs_and_artifacts(modeladmin, request, queryset): removed_files = 0 for run in queryset: for path in _artifact_paths(run.search_id): try: if path.exists(): path.unlink() removed_files += 1 except Exception: continue count = queryset.count() queryset.delete() modeladmin.message_user( request, f"Deleted {count} runs and {removed_files} artifact files.", ) @admin.register(SiteRun) class SiteRunAdmin(admin.ModelAdmin): list_display = ("created_at", "city", "business", "short_id", "artifact_status", "preview", "download") list_filter = ("city", "business", "created_at") search_fields = ("search_id", "city", "business") readonly_fields = ("created_at", "search_id", "city", "business", "payload_json", "result_json") actions = [delete_runs_and_artifacts] def short_id(self, obj: SiteRun) -> str: return obj.search_id[:8] def preview(self, obj: SiteRun): if obj.map_url: return format_html('map', obj.map_url) return "—" def download(self, obj: SiteRun): # if you added a PNG/CSV download endpoint, link it here later url = (obj.result_json or {}).get("download_url") if url: return format_html('download', url) return "—" def artifact_status(self, obj: SiteRun) -> bool: return (Path(settings.MEDIA_ROOT) / "sites" / f"run_{obj.search_id}.json").exists() artifact_status.boolean = True artifact_status.short_description = "Artifacts"