fix: stabilize post-MVP travel-agent and itinerary workflows
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.utils import timezone
|
||||
|
||||
from adventures.models import Collection, CollectionItineraryItem
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = (
|
||||
"Export Collection and CollectionItineraryItem data to a JSON backup "
|
||||
"file before upgrades/migrations."
|
||||
)
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
type=str,
|
||||
help="Optional output file path (default: ./collections_backup_<timestamp>.json)",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
backup_timestamp = timezone.now()
|
||||
timestamp = backup_timestamp.strftime("%Y%m%d_%H%M%S")
|
||||
output_path = Path(
|
||||
options.get("output") or f"collections_backup_{timestamp}.json"
|
||||
)
|
||||
|
||||
if output_path.parent and not output_path.parent.exists():
|
||||
raise CommandError(f"Output directory does not exist: {output_path.parent}")
|
||||
|
||||
collections = list(
|
||||
Collection.objects.values(
|
||||
"id",
|
||||
"user_id",
|
||||
"name",
|
||||
"description",
|
||||
"is_public",
|
||||
"is_archived",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"link",
|
||||
"primary_image_id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
)
|
||||
)
|
||||
|
||||
shared_with_map = {
|
||||
str(collection.id): list(
|
||||
collection.shared_with.values_list("id", flat=True)
|
||||
)
|
||||
for collection in Collection.objects.prefetch_related("shared_with")
|
||||
}
|
||||
for collection in collections:
|
||||
collection["shared_with_ids"] = shared_with_map.get(
|
||||
str(collection["id"]), []
|
||||
)
|
||||
|
||||
itinerary_items = list(
|
||||
CollectionItineraryItem.objects.select_related("content_type").values(
|
||||
"id",
|
||||
"collection_id",
|
||||
"content_type_id",
|
||||
"content_type__app_label",
|
||||
"content_type__model",
|
||||
"object_id",
|
||||
"date",
|
||||
"is_global",
|
||||
"order",
|
||||
"created_at",
|
||||
)
|
||||
)
|
||||
|
||||
backup_payload = {
|
||||
"backup_type": "collections_snapshot",
|
||||
"timestamp": backup_timestamp.isoformat(),
|
||||
"counts": {
|
||||
"collections": len(collections),
|
||||
"collection_itinerary_items": len(itinerary_items),
|
||||
},
|
||||
"collections": collections,
|
||||
"collection_itinerary_items": itinerary_items,
|
||||
}
|
||||
|
||||
try:
|
||||
with output_path.open("w", encoding="utf-8") as backup_file:
|
||||
json.dump(backup_payload, backup_file, indent=2, cls=DjangoJSONEncoder)
|
||||
except OSError as exc:
|
||||
raise CommandError(f"Failed to write backup file: {exc}") from exc
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise CommandError(f"Failed to serialize backup data: {exc}") from exc
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(
|
||||
"Exported collections backup to "
|
||||
f"{output_path} "
|
||||
f"at {backup_timestamp.isoformat()} "
|
||||
f"(collections: {len(collections)}, "
|
||||
f"itinerary_items: {len(itinerary_items)})."
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user