72 lines
2.6 KiB
Python
72 lines
2.6 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from django.core.management.base import BaseCommand
|
|
|
|
from apps.blog.models import Post
|
|
from apps.events.models import Event
|
|
from apps.gallery.models import Gallery
|
|
from apps.users.models import User
|
|
from core.media import safe_process_public_image
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class BackfillTarget:
|
|
label: str
|
|
queryset: object
|
|
field_name: str
|
|
family: str
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = "Generate missing public image derivatives for existing media."
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
"--force",
|
|
action="store_true",
|
|
help="Regenerate derivatives even when sidecar files already exist.",
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
force = options["force"]
|
|
processed = 0
|
|
skipped = 0
|
|
failed = 0
|
|
|
|
targets = (
|
|
BackfillTarget("events", Event.objects.exclude(featured_image="").exclude(featured_image__isnull=True), "featured_image", "event_featured"),
|
|
BackfillTarget("gallery", Gallery.objects.exclude(image="").exclude(image__isnull=True), "image", "gallery"),
|
|
BackfillTarget("blog", Post.objects.exclude(featured_image="").exclude(featured_image__isnull=True), "featured_image", "blog_featured"),
|
|
BackfillTarget("users", User.objects.exclude(profile_picture="").exclude(profile_picture__isnull=True), "profile_picture", "profile_picture"),
|
|
)
|
|
|
|
for target in targets:
|
|
self.stdout.write(self.style.NOTICE(f"Backfilling {target.label}..."))
|
|
for instance in target.queryset.iterator():
|
|
file_field = getattr(instance, target.field_name)
|
|
result = safe_process_public_image(file_field, target.family, force=force)
|
|
if result is None:
|
|
failed += 1
|
|
self.stdout.write(self.style.WARNING(f"failed: {target.label}#{instance.pk}"))
|
|
continue
|
|
|
|
if hasattr(instance, "file_size") and hasattr(instance, "width") and hasattr(instance, "height"):
|
|
type(instance).objects.filter(pk=instance.pk).update(
|
|
file_size=result.file_size,
|
|
width=result.width,
|
|
height=result.height,
|
|
)
|
|
|
|
if result.processed:
|
|
processed += 1
|
|
else:
|
|
skipped += 1
|
|
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f"Media derivative backfill finished. processed={processed} skipped={skipped} failed={failed}"
|
|
)
|
|
)
|