chore: 增加今日订单展示假单灌入脚本
This commit is contained in:
1 parent
0d0b4810f9
commit
4c7f273cf7
1 file changed
+238
@@ -0,0 +1,238 @@
|
||||
"""
|
||||
灌入「今日订单」展示假单(TodayOrderFake),与抢单池 FakeGrabOrder 无关。
|
||||
|
||||
用法(服务器项目根目录):
|
||||
python manage.py seed_today_order_fakes --club-id xq
|
||||
python manage.py seed_today_order_fakes --club-id xq --count 500
|
||||
python manage.py seed_today_order_fakes --club-id xq --clear # 先清该俱乐部旧假单再灌
|
||||
python manage.py seed_today_order_fakes --club-id xq --dry-run
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from decimal import Decimal
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from orders.models import TodayOrderFake
|
||||
|
||||
|
||||
# 用户提供的介绍模板 + 价格(原样,不改写)
|
||||
TEMPLATES = [
|
||||
(
|
||||
'绝密清图撤离1把,一直无法清图则保底2000万,所有的变卖和装备都归老板保持良好的服务态度',
|
||||
'35.00',
|
||||
),
|
||||
(
|
||||
'保底305W-800W【不卡保底老板自选图】机密',
|
||||
'20.00',
|
||||
),
|
||||
(
|
||||
'机密200W,打手打完之后一定要提供相关明确的老板主页,战绩,收益,证据截图',
|
||||
'13.00',
|
||||
),
|
||||
(
|
||||
'绝密清图保底310W-777W【不卡保底老板自选图】别试图蒙混,让老板挑刺',
|
||||
'23.00',
|
||||
),
|
||||
(
|
||||
'不卡保底444W~999W,打手打完之后一定要提供相关明确的老板主页,战绩,收益,证据截图',
|
||||
'33.00',
|
||||
),
|
||||
(
|
||||
'金牌护航,绝密清图,不卡保底2026W~2888W,所有的变卖和装备都归老板保持良好的服务态度',
|
||||
'200.00',
|
||||
),
|
||||
(
|
||||
'绝密清图单局800W,打手别让老板来挑刺,打手打完之后一定要提供相关明确的老板主页,战绩,收益,证据截图',
|
||||
'80.00',
|
||||
),
|
||||
(
|
||||
'护航600万(上不封顶),打手打完之后一定要提供相关明确的老板主页,战绩,收益,证据截图',
|
||||
'50.00',
|
||||
),
|
||||
(
|
||||
'绝密老板选图749W-1769W,炸弹一把加60w',
|
||||
'65.00',
|
||||
),
|
||||
(
|
||||
'绝密清图单局555W,别让老板来挑刺,打手打完之后一定要提供相关明确的老板主页,战绩,收益,证据截图',
|
||||
'50.00',
|
||||
),
|
||||
(
|
||||
'保底105W-555W【不卡保底】机密,打手打完之后一定要提供相关明确的老板主页,战绩,收益,证据截图',
|
||||
'7.50',
|
||||
),
|
||||
(
|
||||
'绝密连续清图撤离两把断一把重新打,所有的变卖和装备都归老板保持良好的服务态度',
|
||||
'75.00',
|
||||
),
|
||||
(
|
||||
'绝密赌老板自选图单局一个随机红,打手打完之后一定要提供相关明确的老板主页,战绩,收益,证据截图',
|
||||
'25.00',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _rel_media(path: str) -> str:
|
||||
p = (path or '').strip()
|
||||
if not p:
|
||||
return ''
|
||||
for prefix in ('https://', 'http://'):
|
||||
if p.startswith(prefix):
|
||||
# 取域名后路径
|
||||
rest = p.split('://', 1)[-1]
|
||||
slash = rest.find('/')
|
||||
return rest[slash + 1 :] if slash >= 0 else ''
|
||||
return p.lstrip('/')
|
||||
|
||||
|
||||
def _resolve_sanjiaozhou(club_id: str, leixing_id: int | None):
|
||||
"""解析三角洲类型 id + 图标相对 URL。"""
|
||||
from products.models import ShangpinLeixing
|
||||
from jituan.models import ClubShangpinLeixingConfig
|
||||
|
||||
lx = None
|
||||
if leixing_id:
|
||||
lx = ShangpinLeixing.query.filter(id=int(leixing_id)).first()
|
||||
if not lx:
|
||||
raise CommandError(f'找不到商品类型 id={leixing_id}')
|
||||
else:
|
||||
qs = ShangpinLeixing.query.filter(jieshao__icontains='三角洲').order_by('id')
|
||||
rows = list(qs)
|
||||
if not rows:
|
||||
raise CommandError('库里没有名称含「三角洲」的商品类型,请用 --leixing-id 指定')
|
||||
# 优先俱乐部已上架的
|
||||
enabled_ids = set(
|
||||
ClubShangpinLeixingConfig.query.filter(
|
||||
club_id=club_id, is_enabled=True,
|
||||
).values_list('leixing_id', flat=True)
|
||||
)
|
||||
preferred = [r for r in rows if r.id in enabled_ids] or rows
|
||||
lx = preferred[0]
|
||||
|
||||
image = ''
|
||||
cfg = ClubShangpinLeixingConfig.query.filter(
|
||||
club_id=club_id, leixing_id=lx.id,
|
||||
).first()
|
||||
if cfg and (cfg.tupian_url or '').strip():
|
||||
image = _rel_media(cfg.tupian_url)
|
||||
if not image:
|
||||
image = _rel_media(lx.tupian_url or '')
|
||||
if not image:
|
||||
raise CommandError(
|
||||
f'三角洲类型 id={lx.id}({lx.jieshao})没有图标 URL,'
|
||||
f'请先在后台配置类型图或俱乐部专属图标'
|
||||
)
|
||||
return int(lx.id), image, (lx.jieshao or '')
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '灌入今日订单展示假单 TodayOrderFake(默认 500 条,模板循环随机)'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--club-id', default='xq', help='俱乐部 ID,默认 xq')
|
||||
parser.add_argument('--count', type=int, default=500, help='灌入条数,默认 500')
|
||||
parser.add_argument(
|
||||
'--leixing-id', type=int, default=None,
|
||||
help='商品类型 ID;默认自动找名称含「三角洲」的类型',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--merchant-ratio', type=float, default=0.75,
|
||||
help='商家单占比,默认 0.75(其余为平台单)',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--done-ratio', type=float, default=0.70,
|
||||
help='已完成占比,默认 0.70(其余为进行中)',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--clear', action='store_true',
|
||||
help='灌入前删除该俱乐部全部 TodayOrderFake',
|
||||
)
|
||||
parser.add_argument('--dry-run', action='store_true', help='只打印不写库')
|
||||
parser.add_argument('--seed', type=int, default=None, help='随机种子(可复现)')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
club_id = (options['club_id'] or 'xq').strip()
|
||||
count = max(1, int(options['count'] or 500))
|
||||
merchant_ratio = float(options['merchant_ratio'])
|
||||
done_ratio = float(options['done_ratio'])
|
||||
dry = bool(options['dry_run'])
|
||||
if options['seed'] is not None:
|
||||
random.seed(int(options['seed']))
|
||||
|
||||
leixing_id, image_url, lx_name = _resolve_sanjiaozhou(club_id, options['leixing_id'])
|
||||
|
||||
self.stdout.write(
|
||||
f'club={club_id} leixing={leixing_id}({lx_name}) '
|
||||
f'image={image_url} count={count} '
|
||||
f'merchant={merchant_ratio:.0%} done={done_ratio:.0%}'
|
||||
)
|
||||
self.stdout.write(f'模板数={len(TEMPLATES)} dry_run={dry} clear={options["clear"]}')
|
||||
|
||||
if dry:
|
||||
# 抽样预览
|
||||
for i in range(min(5, count)):
|
||||
jieshao, price = random.choice(TEMPLATES)
|
||||
plat = 2 if random.random() < merchant_ratio else 1
|
||||
st = TodayOrderFake.STATUS_DONE if random.random() < done_ratio else TodayOrderFake.STATUS_DOING
|
||||
self.stdout.write(
|
||||
f' sample[{i}] platform={plat} status={st} price={price} | {jieshao[:40]}...'
|
||||
)
|
||||
self.stdout.write(self.style.WARNING('dry-run:未写入数据库'))
|
||||
return
|
||||
|
||||
with transaction.atomic():
|
||||
if options['clear']:
|
||||
deleted, _ = TodayOrderFake.query.filter(club_id=club_id).delete()
|
||||
self.stdout.write(f'已清理 club={club_id} 旧假单 {deleted} 条')
|
||||
|
||||
now = timezone.now()
|
||||
if timezone.is_aware(now):
|
||||
try:
|
||||
now = timezone.make_naive(now)
|
||||
except Exception:
|
||||
pass
|
||||
rows = []
|
||||
for i in range(count):
|
||||
jieshao, price = random.choice(TEMPLATES)
|
||||
platform = (
|
||||
TodayOrderFake.PLATFORM_SHANGJIA
|
||||
if random.random() < merchant_ratio
|
||||
else TodayOrderFake.PLATFORM_PINGTAI
|
||||
)
|
||||
status = (
|
||||
TodayOrderFake.STATUS_DONE
|
||||
if random.random() < done_ratio
|
||||
else TodayOrderFake.STATUS_DOING
|
||||
)
|
||||
rows.append(
|
||||
TodayOrderFake(
|
||||
club_id=club_id,
|
||||
platform=platform,
|
||||
leixing_id=leixing_id,
|
||||
jieshao=jieshao,
|
||||
price=Decimal(price),
|
||||
image_url=image_url,
|
||||
status=status,
|
||||
is_active=True,
|
||||
sort_order=count - i,
|
||||
CreateTime=now,
|
||||
UpdateTime=now,
|
||||
)
|
||||
)
|
||||
TodayOrderFake.objects.bulk_create(rows, batch_size=200)
|
||||
|
||||
total = TodayOrderFake.query.filter(club_id=club_id, is_active=True).count()
|
||||
done_n = TodayOrderFake.query.filter(
|
||||
club_id=club_id, is_active=True, status=TodayOrderFake.STATUS_DONE,
|
||||
).count()
|
||||
sj_n = TodayOrderFake.query.filter(
|
||||
club_id=club_id, is_active=True, platform=TodayOrderFake.PLATFORM_SHANGJIA,
|
||||
).count()
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'完成:新写入 {count} 条;当前启用假单共 {total} 条 '
|
||||
f'(已完成 {done_n},商家单 {sj_n})'
|
||||
))
|
||||
Reference in new issue
Block a user