diff --git a/jituan/management/commands/import_ufo_catalog.py b/jituan/management/commands/import_ufo_catalog.py index e9ca175..b151219 100644 --- a/jituan/management/commands/import_ufo_catalog.py +++ b/jituan/management/commands/import_ufo_catalog.py @@ -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=\n' - ' ./venv/bin/python manage.py import_ufo_catalog --leixing-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]