fix: UFO 导入默认精确匹配类型名「三角洲」并写俱乐部上架表

不模糊匹配;ClubShangpinLeixingConfig(ufo) 上架 + 商品/专区挂同一 leixing_id。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-22 23:28:40 +08:00
parent 93580a6d63
commit e722c7016d

View File

@@ -3,20 +3,18 @@
将原 UFO 站点商品目录灌入星阙,且只写 club_id=ufo。
默认 dry-run只打印计划不写库。真正写入必须加 --apply。
【必须】用 --leixing-id 指定三角洲类型主键,禁止靠模糊名字瞎挂
默认按全局类型名「三角洲」**全名精确匹配**找 id不含这三字的一律不要
找到唯一一条后:
1) ClubShangpinLeixingConfig 给 club=ufo 上架该类型
2) ShangpinZhuanqu / Shangpin 的 leixing_id 挂这个全局类型 id且 club_id=ufo
服务器上(复制整段):
cd /opt/1panel/apps/openresty/nginx/www/sites/43.142.166.152.443/django
git pull origin main
# 先看全部类型 id核对哪一行是三角洲
./venv/bin/python manage.py import_ufo_catalog --list-leixing
# 假设核对后 id=3示例以你库里为准
./venv/bin/python manage.py import_ufo_catalog --leixing-id=3
./venv/bin/python manage.py import_ufo_catalog --leixing-id=3 --apply
./venv/bin/python manage.py import_ufo_catalog --leixing-id=3 --apply --with-banners
./venv/bin/python manage.py import_ufo_catalog
./venv/bin/python manage.py import_ufo_catalog --apply
./venv/bin/python manage.py import_ufo_catalog --apply --with-banners
"""
from __future__ import annotations
@@ -35,12 +33,12 @@ from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
TARGET_CLUB = 'ufo'
EXPECTED_NAME_HINT = '三角洲'
DEFAULT_LEIXING_NAME = '三角洲' # 全名精确匹配,不模糊
DEFAULT_CATALOG = Path(__file__).resolve().parents[2] / 'data' / 'ufo_catalog.json'
class Command(BaseCommand):
help = '导入 UFO 商品/专区到 club_id=ufo默认 dry-run必须 --leixing-id'
help = '导入 UFO 商品/专区到 club_id=ufo默认 dry-run类型名默认精确匹配「三角洲」'
def add_arguments(self, parser):
parser.add_argument('--apply', action='store_true', help='真正写库(仅 ufo')
@@ -48,19 +46,19 @@ class Command(BaseCommand):
parser.add_argument(
'--list-leixing',
action='store_true',
help='只列出全局商品类型 id/名称,用来核对三角洲真实 id',
help='只列出全局商品类型 id/名称',
)
parser.add_argument(
'--leixing-id',
type=int,
default=0,
help='【必填,推荐】全局商品类型主键。先 --list-leixing 核对',
help='可选:直接指定全局类型主键;不传则按 --leixing-name 精确匹配',
)
parser.add_argument(
'--leixing-name',
type=str,
default='',
help='未传 id 时:按 jieshao全名精确匹配」且必须唯一;禁止模糊匹配',
default=DEFAULT_LEIXING_NAME,
help='全局 ShangpinLeixing.jieshao 全名精确匹配,默认:三角洲',
)
parser.add_argument('--with-banners', action='store_true', help='同时导入点单主轮播+第二横幅')
parser.add_argument('--skip-oss', action='store_true', help='不上传 OSS保留原 URL应急')
@@ -70,17 +68,16 @@ class Command(BaseCommand):
from products.models import ShangpinLeixing
if options.get('list_leixing'):
self.stdout.write('全局商品类型清单:')
self.stdout.write('全局商品类型清单ShangpinLeixing')
for lx in ShangpinLeixing.query.order_by('id'):
mark = ' <<-- 名称含三角洲' if EXPECTED_NAME_HINT in (lx.jieshao or '') else ''
mark = ' <<-- 精确名=三角洲' if (lx.jieshao or '') == DEFAULT_LEIXING_NAME else ''
self.stdout.write(
f' id={lx.id} name={lx.jieshao!r} '
f'shenhezhuangtai={lx.shenhezhuangtai} paixu={lx.paixu}{mark}'
)
self.stdout.write(self.style.NOTICE(
'请人工确认「三角洲」那一行的 id再执行\n'
' ./venv/bin/python manage.py import_ufo_catalog --leixing-id=<id>\n'
' ./venv/bin/python manage.py import_ufo_catalog --leixing-id=<id> --apply'
'默认会精确匹配 name==「三角洲」;也可 --leixing-id=... 覆盖。\n'
'俱乐部上架表 ClubShangpinLeixingConfig 会在 --apply 时给 ufo 自动开启该类型。'
))
return
@@ -125,12 +122,18 @@ class Command(BaseCommand):
raise CommandError(
f'类型 id={leixing.id}{leixing.jieshao}」是审核专用,拒绝挂载'
)
if EXPECTED_NAME_HINT not in (leixing.jieshao or ''):
expect_name = (options.get('leixing_name') or DEFAULT_LEIXING_NAME).strip()
if (leixing.jieshao or '') != expect_name and not int(options.get('leixing_id') or 0):
raise CommandError(
f'安全拦截:类型 id={leixing.id} 名称是「{leixing.jieshao}」,'
f'不含「{EXPECTED_NAME_HINT}」。请重新 --list-leixing 核对后再传正确 --leixing-id'
f'安全拦截:解析到的类型名是「{leixing.jieshao}」,'
f'与要求的精确名「{expect_name}」不一致'
)
self.stdout.write(
f'将写入ClubShangpinLeixingConfig(club=ufo, leixing_id={leixing.id}, is_enabled=True)'
f'专区/商品 leixing_id={leixing.id}, club_id=ufo'
)
for z in zones:
self.stdout.write(f' 专区: {z.get("name")} goods={len(z.get("goods_ids") or [])}')
for p in products[:5]:
@@ -142,9 +145,9 @@ class Command(BaseCommand):
if not apply:
self.stdout.write(self.style.WARNING(
'当前 dry-run未写库。确认类型 id 无误后:\n'
f' ./venv/bin/python manage.py import_ufo_catalog --leixing-id={leixing.id} --apply\n'
f' ./venv/bin/python manage.py import_ufo_catalog --leixing-id={leixing.id} --apply --with-banners'
'当前 dry-run未写库。确认无误后\n'
' ./venv/bin/python manage.py import_ufo_catalog --apply\n'
' ./venv/bin/python manage.py import_ufo_catalog --apply --with-banners'
))
return
@@ -340,35 +343,31 @@ class Command(BaseCommand):
))
def _resolve_leixing(self, ShangpinLeixing, leixing_id: int, leixing_name: str):
"""必须用 id字仅作精确匹配兜底,且必须唯一。"""
"""优先 id否则 jieshao 全名精确匹配且必须唯一。不做 icontains。"""
if leixing_id:
try:
return ShangpinLeixing.query.get(id=leixing_id)
lx = ShangpinLeixing.query.get(id=leixing_id)
except ShangpinLeixing.DoesNotExist as exc:
raise CommandError(f'类型 id={leixing_id} 不存在') from exc
return lx
name = (leixing_name or '').strip()
if not name:
raise CommandError(
'必须指定类型,先执行:\n'
' ./venv/bin/python manage.py import_ufo_catalog --list-leixing\n'
'再:\n'
' ./venv/bin/python manage.py import_ufo_catalog --leixing-id=<三角洲的id>'
)
rows = list(ShangpinLeixing.query.filter(jieshao=name).order_by('id'))
name = (leixing_name or DEFAULT_LEIXING_NAME).strip() or DEFAULT_LEIXING_NAME
rows = list(
ShangpinLeixing.query.filter(jieshao=name)
.exclude(shenhezhuangtai=2)
.order_by('id')
)
if not rows:
# 列出接近的,方便人工选
near = list(
ShangpinLeixing.query.filter(jieshao__icontains=name).order_by('id')[:20]
)
hint = '\n'.join(
f' id={x.id} name={x.jieshao!r} shenhezhuangtai={x.shenhezhuangtai}'
for x in near
) or ' (无近似匹配'
) or ' (无近似)'
raise CommandError(
f'找不到全名精确等于「{name}」的类型。近似:\n{hint}\n'
' --leixing-id=... 明确指定。'
f'找不到 jieshao 精确等于「{name}且非审核专用的类型。库中近似:\n{hint}\n'
'先在后台把类型名改成正好「三角洲」,或 --leixing-id=... 指定。'
)
if len(rows) > 1:
detail = '\n'.join(
@@ -376,8 +375,7 @@ class Command(BaseCommand):
for x in rows
)
raise CommandError(
f'名称{name}」匹配到多条,拒绝自动选,避免挂错:\n{detail}\n'
'请用 --leixing-id=... 指定其中一条。'
f'{name}精确匹配到多条,拒绝自动选,避免挂错:\n{detail}'
)
return rows[0]