Coverage for extras/management/commands/populate_image_sizes.py: 0%
37 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.core.management.base import BaseCommand
3from extras.models import ImageAttachment
5# Number of records to read and write per batch
6BATCH_SIZE = 100
9class Command(BaseCommand):
10 help = "Populate the image_size field for ImageAttachments that predate it"
12 def handle(self, *args, **options):
13 verbosity = options['verbosity']
15 # Only consider attachments whose size has not yet been cached. This is safe to re-run: rows whose file
16 # was unreadable on a previous run remain NULL and will be retried.
17 queryset = ImageAttachment.objects.filter(image_size__isnull=True)
18 total = queryset.count()
20 if not total:
21 if verbosity:
22 self.stdout.write(self.style.SUCCESS("No image attachments require updating."))
23 return
25 if verbosity:
26 self.stdout.write(f"Populating image_size for {total} image attachment(s)...")
28 updated = 0
29 skipped = 0
30 batch = []
32 for processed, attachment in enumerate(queryset.iterator(chunk_size=BATCH_SIZE), start=1):
33 # These rows have image_size=NULL, so the size property reads the file from storage (returning None if
34 # it's inaccessible) rather than returning a cached value.
35 size = attachment.size
36 if size is None:
37 # File is inaccessible; leave image_size NULL so a future run can retry.
38 skipped += 1
39 else:
40 attachment.image_size = size
41 batch.append(attachment)
43 if len(batch) >= BATCH_SIZE:
44 ImageAttachment.objects.bulk_update(batch, ['image_size'])
45 updated += len(batch)
46 batch = []
48 # Reading each file's size may issue a request to the storage backend, so emit periodic progress
49 # for large tables rather than going silent until completion.
50 if verbosity and processed % BATCH_SIZE == 0:
51 self.stdout.write(f" Processed {processed}/{total}...")
53 if batch:
54 ImageAttachment.objects.bulk_update(batch, ['image_size'])
55 updated += len(batch)
57 if verbosity:
58 self.stdout.write(self.style.SUCCESS(f"Updated {updated} image attachment(s)."))
59 if skipped:
60 self.stdout.write(self.style.WARNING(
61 f"Skipped {skipped} inaccessible file(s); re-run this command to retry them."
62 ))