From bc29118a6e19ff30d28a5264baab4c63f239e302 Mon Sep 17 00:00:00 2001 From: XingQue Date: Wed, 22 Jul 2026 23:34:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20UFO=20=E5=AF=BC=E5=85=A5=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E8=B7=AF=E5=BE=84=E5=AF=B9=E9=BD=90=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=EF=BC=8C=E5=A4=B1=E8=B4=A5=E4=B8=8D=E5=86=99?= =?UTF-8?q?=E5=A4=96=E7=AB=99=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 商品/专区/规则/轮播分别进 shangpin/shangpintupian、zhuanqu、guize、a_long/lunbo;库只存相对路径。 Co-authored-by: Cursor --- .../management/commands/import_ufo_catalog.py | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/jituan/management/commands/import_ufo_catalog.py b/jituan/management/commands/import_ufo_catalog.py index b151219..2e3c31d 100644 --- a/jituan/management/commands/import_ufo_catalog.py +++ b/jituan/management/commands/import_ufo_catalog.py @@ -163,24 +163,20 @@ class Command(BaseCommand): } def to_oss(url: str, prefix: str) -> str: + """下载原图 → 上传到本站 OSS → 返回相对路径(与后台 AddProduct 一致)。""" if not url: return '' if skip_oss: + # 应急:允许写完整 URL;正式导入不要加 --skip-oss return url if not str(url).startswith('http'): return url - try: - path = self._upload_remote(url, prefix) - if path: - stats['oss_ok'] += 1 - return path + path = self._upload_remote(url, prefix) + if not path: stats['oss_fail'] += 1 - self.stderr.write(f'OSS 失败,保留原 URL: {url}') - return url - except Exception as exc: # noqa: BLE001 - stats['oss_fail'] += 1 - self.stderr.write(f'OSS 异常 {url}: {exc}') - return url + raise CommandError(f'OSS 上传失败,已中止以免库里写入外站链接: {url}') + stats['oss_ok'] += 1 + return path with transaction.atomic(): cfg, created = ClubShangpinLeixingConfig.query.get_or_create( @@ -205,7 +201,7 @@ class Command(BaseCommand): if not name: continue src_id = int(z.get('source_id') or 0) - thumb = to_oss(z.get('thumb_url') or '', f'ufo/zones/{src_id or idx}') + thumb = to_oss(z.get('thumb_url') or '', 'shangpin/zhuanqu') row = ShangpinZhuanqu.query.filter( club_id=TARGET_CLUB, mingzi=name, @@ -253,9 +249,9 @@ class Command(BaseCommand): pics = list(p.get('pics_url') or []) thumb = p.get('thumb_url') or (pics[0] if pics else '') - tupian = to_oss(thumb, f'ufo/products/{p.get("source_id")}') + tupian = to_oss(thumb, 'shangpin/shangpintupian') rule_imgs = list(p.get('rule_images_url') or []) - guize = to_oss(rule_imgs[0], f'ufo/rules/{p.get("source_id")}') if rule_imgs else '' + guize = to_oss(rule_imgs[0], 'shangpin/guize') if rule_imgs else '' weigh = int(p.get('weigh') or p.get('home_weigh') or 0) on_shelf = int(p.get('status') or 1) == 1 @@ -319,7 +315,7 @@ class Command(BaseCommand): ImageType=image_type, ).delete() for b in items: - url = to_oss(b.get('url') or '', f'ufo/lunbo/{page_key}') + url = to_oss(b.get('url') or '', 'a_long/lunbo') if not url: continue Lunbo.query.create( @@ -388,13 +384,19 @@ class Command(BaseCommand): @staticmethod def _upload_remote(url: str, prefix: str) -> str: + """返回 OSS 相对 key;失败返回空串。与后台一致:DB 只存相对路径。""" + from datetime import datetime + from utils.oss_utils import upload_to_oss - ctx = ssl.create_default_context() - req = Request(url, headers={'User-Agent': 'UFO-Import/1.0'}) - with urlopen(req, timeout=60, context=ctx) as resp: - raw = resp.read() - ctype = resp.headers.get('Content-Type') or '' + try: + ctx = ssl.create_default_context() + req = Request(url, headers={'User-Agent': 'UFO-Import/1.0'}) + with urlopen(req, timeout=60, context=ctx) as resp: + raw = resp.read() + ctype = resp.headers.get('Content-Type') or '' + except Exception: # noqa: BLE001 + return '' ext = mimetypes.guess_extension((ctype or '').split(';')[0].strip()) or '' if not ext or ext == '.jpe': @@ -403,10 +405,11 @@ class Command(BaseCommand): if ext == '.jpeg': ext = '.jpg' - rel = f"{prefix.strip('/')}/{uuid.uuid4().hex[:10]}{ext}" + ts = datetime.now().strftime('%Y%m%d%H%M%S') + rel = f"{prefix.strip('/')}/{ts}_{uuid.uuid4().hex[:8]}{ext}" bio = BytesIO(raw) bio.name = os.path.basename(rel) ok = upload_to_oss(bio, rel) if not ok: return '' - return rel + return rel # 关键:只返回相对路径,不返回完整 CDN URL