Files
Django/orders/management/commands/seed_today_order_fakes.py
T

239 lines
9.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
灌入「今日订单」展示假单(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})'
))