fix: UFO 导入图片路径对齐后台目录,失败不写外站 URL
商品/专区/规则/轮播分别进 shangpin/shangpintupian、zhuanqu、guize、a_long/lunbo;库只存相对路径。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -163,24 +163,20 @@ class Command(BaseCommand):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def to_oss(url: str, prefix: str) -> str:
|
def to_oss(url: str, prefix: str) -> str:
|
||||||
|
"""下载原图 → 上传到本站 OSS → 返回相对路径(与后台 AddProduct 一致)。"""
|
||||||
if not url:
|
if not url:
|
||||||
return ''
|
return ''
|
||||||
if skip_oss:
|
if skip_oss:
|
||||||
|
# 应急:允许写完整 URL;正式导入不要加 --skip-oss
|
||||||
return url
|
return url
|
||||||
if not str(url).startswith('http'):
|
if not str(url).startswith('http'):
|
||||||
return url
|
return url
|
||||||
try:
|
path = self._upload_remote(url, prefix)
|
||||||
path = self._upload_remote(url, prefix)
|
if not path:
|
||||||
if path:
|
|
||||||
stats['oss_ok'] += 1
|
|
||||||
return path
|
|
||||||
stats['oss_fail'] += 1
|
stats['oss_fail'] += 1
|
||||||
self.stderr.write(f'OSS 失败,保留原 URL: {url}')
|
raise CommandError(f'OSS 上传失败,已中止以免库里写入外站链接: {url}')
|
||||||
return url
|
stats['oss_ok'] += 1
|
||||||
except Exception as exc: # noqa: BLE001
|
return path
|
||||||
stats['oss_fail'] += 1
|
|
||||||
self.stderr.write(f'OSS 异常 {url}: {exc}')
|
|
||||||
return url
|
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
cfg, created = ClubShangpinLeixingConfig.query.get_or_create(
|
cfg, created = ClubShangpinLeixingConfig.query.get_or_create(
|
||||||
@@ -205,7 +201,7 @@ class Command(BaseCommand):
|
|||||||
if not name:
|
if not name:
|
||||||
continue
|
continue
|
||||||
src_id = int(z.get('source_id') or 0)
|
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(
|
row = ShangpinZhuanqu.query.filter(
|
||||||
club_id=TARGET_CLUB,
|
club_id=TARGET_CLUB,
|
||||||
mingzi=name,
|
mingzi=name,
|
||||||
@@ -253,9 +249,9 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
pics = list(p.get('pics_url') or [])
|
pics = list(p.get('pics_url') or [])
|
||||||
thumb = p.get('thumb_url') or (pics[0] if pics else '')
|
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 [])
|
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)
|
weigh = int(p.get('weigh') or p.get('home_weigh') or 0)
|
||||||
on_shelf = int(p.get('status') or 1) == 1
|
on_shelf = int(p.get('status') or 1) == 1
|
||||||
@@ -319,7 +315,7 @@ class Command(BaseCommand):
|
|||||||
ImageType=image_type,
|
ImageType=image_type,
|
||||||
).delete()
|
).delete()
|
||||||
for b in items:
|
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:
|
if not url:
|
||||||
continue
|
continue
|
||||||
Lunbo.query.create(
|
Lunbo.query.create(
|
||||||
@@ -388,13 +384,19 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _upload_remote(url: str, prefix: str) -> str:
|
def _upload_remote(url: str, prefix: str) -> str:
|
||||||
|
"""返回 OSS 相对 key;失败返回空串。与后台一致:DB 只存相对路径。"""
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from utils.oss_utils import upload_to_oss
|
from utils.oss_utils import upload_to_oss
|
||||||
|
|
||||||
ctx = ssl.create_default_context()
|
try:
|
||||||
req = Request(url, headers={'User-Agent': 'UFO-Import/1.0'})
|
ctx = ssl.create_default_context()
|
||||||
with urlopen(req, timeout=60, context=ctx) as resp:
|
req = Request(url, headers={'User-Agent': 'UFO-Import/1.0'})
|
||||||
raw = resp.read()
|
with urlopen(req, timeout=60, context=ctx) as resp:
|
||||||
ctype = resp.headers.get('Content-Type') or ''
|
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 ''
|
ext = mimetypes.guess_extension((ctype or '').split(';')[0].strip()) or ''
|
||||||
if not ext or ext == '.jpe':
|
if not ext or ext == '.jpe':
|
||||||
@@ -403,10 +405,11 @@ class Command(BaseCommand):
|
|||||||
if ext == '.jpeg':
|
if ext == '.jpeg':
|
||||||
ext = '.jpg'
|
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 = BytesIO(raw)
|
||||||
bio.name = os.path.basename(rel)
|
bio.name = os.path.basename(rel)
|
||||||
ok = upload_to_oss(bio, rel)
|
ok = upload_to_oss(bio, rel)
|
||||||
if not ok:
|
if not ok:
|
||||||
return ''
|
return ''
|
||||||
return rel
|
return rel # 关键:只返回相对路径,不返回完整 CDN URL
|
||||||
|
|||||||
Reference in New Issue
Block a user