1
0
forked from erp-dev/erp

fix: change backfill product image

This commit is contained in:
2026-03-25 16:27:11 +08:00
parent 412bd09296
commit aa97e61c89
2 changed files with 180 additions and 59 deletions

View File

@@ -2,11 +2,11 @@ from django.core.management.base import BaseCommand, CommandError
from django.db.models import Q
from api_v1.tasks import _fetch_external_product_image, _upload_product_image
from basic_info.models import Product
from printing.models import PrintingJob
class Command(BaseCommand):
help = ' image 为空但 get_primary_image_url() 非空的 Product 通过外部 image API 回补图片'
help = '来自外部印染订单的生产子单所关联且 image 为空的 Product 通过 external_raw.YanSe 回补图片'
def add_arguments(self, parser):
parser.add_argument('--merchant-id', type=int, help='仅处理指定商户的产品')
@@ -18,24 +18,33 @@ class Command(BaseCommand):
help='仅输出将处理的产品,不实际请求外部 API 或写库',
)
@staticmethod
def _extract_request_name(job: PrintingJob) -> str:
raw = job.external_raw or {}
if isinstance(raw, dict):
request_name = str(raw.get('YanSe') or '').strip()
if request_name:
return request_name
return str(job.external_product_name or '').strip()
def handle(self, *args, **options):
queryset = Product.objects.filter(
Q(image__isnull=True) | Q(image=''),
).exclude(
name__isnull=True,
).exclude(
name='',
).select_related('merchant')
queryset = (
PrintingJob.objects.filter(
printing_order__external_order_id__isnull=False,
)
.exclude(printing_order__external_order_id='')
.filter(Q(product__image__isnull=True) | Q(product__image=''))
.select_related('product', 'printing_order', 'product__merchant')
.order_by('-id')
)
merchant_id = options.get('merchant_id')
if merchant_id:
queryset = queryset.filter(merchant_id=merchant_id)
queryset = queryset.filter(product__merchant_id=merchant_id)
product_id = options.get('product_id')
if product_id:
queryset = queryset.filter(id=product_id)
queryset = queryset.order_by('-id')
queryset = queryset.filter(product_id=product_id)
limit = options.get('limit')
if limit is not None:
@@ -45,44 +54,60 @@ class Command(BaseCommand):
success_count = 0
failed_count = 0
skipped_count = 0
skipped_no_primary_count = 0
skipped_with_image_count = 0
skipped_without_request_name_count = 0
skipped_duplicate_product_count = 0
selected_count = 0
scanned_count = 0
dry_run = bool(options.get('dry_run'))
seen_product_ids = set()
for product in queryset.iterator(chunk_size=1000):
for job in queryset.iterator(chunk_size=1000):
scanned_count += 1
product = job.product
if product.image:
skipped_count += 1
skipped_with_image_count += 1
continue
if not product.get_primary_image_url():
skipped_no_primary_count += 1
if product.id in seen_product_ids:
skipped_duplicate_product_count += 1
continue
request_name = self._extract_request_name(job)
if not request_name:
skipped_without_request_name_count += 1
continue
seen_product_ids.add(product.id)
selected_count += 1
if dry_run:
self.stdout.write(
f'[DRY-RUN] product_id={product.id} merchant_id={product.merchant_id} name={product.name}'
'[DRY-RUN] '
f'job_id={job.id} '
f'product_id={product.id} '
f'merchant_id={product.merchant_id} '
f'product_name={product.name} '
f'request_name={request_name}'
)
else:
try:
image_payload = _fetch_external_product_image(product.name)
image_payload = _fetch_external_product_image(request_name)
_upload_product_image(product, image_payload)
except Exception as exc:
failed_count += 1
self.stderr.write(
self.style.ERROR(
f'补图失败: product_id={product.id} merchant_id={product.merchant_id} '
f'name={product.name} error={exc}'
f'补图失败: job_id={job.id} product_id={product.id} merchant_id={product.merchant_id} '
f'product_name={product.name} request_name={request_name} error={exc}'
)
)
else:
success_count += 1
self.stdout.write(
self.style.SUCCESS(
f'补图成功: product_id={product.id} merchant_id={product.merchant_id} name={product.name}'
f'补图成功: job_id={job.id} product_id={product.id} merchant_id={product.merchant_id} '
f'product_name={product.name} request_name={request_name}'
)
)
@@ -99,7 +124,8 @@ class Command(BaseCommand):
f'selected={selected_count} '
f'success={success_count} '
f'failed={failed_count} '
f'skipped_with_image={skipped_count} '
f'skipped_without_primary_url={skipped_no_primary_count}'
f'skipped_with_image={skipped_with_image_count} '
f'skipped_without_request_name={skipped_without_request_name_count} '
f'skipped_duplicate_product={skipped_duplicate_product_count}'
)
)