Files
guilan-ace-backend/core/management/commands/backfill_media_derivatives.py
Amirhossein Khalili b4903f7cb1
Some checks failed
Backend CI/CD / test (push) Has been cancelled
Backend CI/CD / deploy (push) Has been cancelled
F(backend): add public media derivatives pipeline
2026-05-20 14:26:51 +03:30

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}"
)
)