perf: P1 性能优化批量修复 + kefu 视图拆分
P1 性能优化(避免循环内 N+1 / N 次 DB 查询): - shop_order_views._batch_images: 移除 ThreadPoolExecutor 掩盖的 N 次查询,改单次批量 + Python 侧分组 - product_query.DashouHuiyuanList: 5N 查询 -> 3 次批量预取 + 本地闭包判断 - roles.GetRolePermissionView / 用户列表: 循环内 RolePermission/Permission/UserRole/Role -> 批量 __in 预取 - guanli / zuzhang 杜次分红 4.2/4.3: 循环内 update_or_create + 单条 delete -> bulk_create + bulk_update + 批量 delete - admin_config QQ 群配置: 循环内 exists/first/save/create -> 批量预取 + bulk_create + bulk_update - jituan 服务层多处合并统计查询、批量预取 map - rank 多处循环 N+1 改批量预取 - backend 多处循环内 count/create 改批量 - config/orders/merchant_ops 多处循环 N+1 改批量预取 其他改动: - users/views/kefu.py 拆分为 kefu_base/kefu_dashou/kefu_orders/kefu_punishment/kefu_withdraw 5 个文件 - 删除遗留脚本 check_prod_uid.py / create_rbac_tables.sql
This commit is contained in:
@@ -364,7 +364,7 @@ class AdGengHuanDaShou(APIView):
|
||||
|
||||
# 8. 验证新打手ID是否存在,并且是打手身份
|
||||
try:
|
||||
new_dashou_user = User.query.get(
|
||||
new_dashou_user = User.query.select_related('DashouProfile').get(
|
||||
UserUID=new_dashou_id,
|
||||
#user_type='PlayerID'
|
||||
)
|
||||
@@ -459,7 +459,7 @@ class AdGengHuanDaShou(APIView):
|
||||
if old_dashou_id:
|
||||
try:
|
||||
# 查询原打手主表
|
||||
old_dashou_user = User.query.get(
|
||||
old_dashou_user = User.query.select_related('DashouProfile').get(
|
||||
UserUID=old_dashou_id,
|
||||
#user_type='PlayerID'
|
||||
)
|
||||
@@ -567,7 +567,7 @@ class AdQiangZhiJieDan(APIView):
|
||||
|
||||
# 6. 查询订单主表
|
||||
try:
|
||||
dingdan_obj = Order.query.get(OrderID=dingdan_id)
|
||||
dingdan_obj = Order.query.select_related('shangjia_kuozhan', 'pingtai_kuozhan').get(OrderID=dingdan_id)
|
||||
except Order.DoesNotExist:
|
||||
return Response(
|
||||
{'code': 404, 'message': '订单不存在', 'data': None},
|
||||
@@ -603,7 +603,7 @@ class AdQiangZhiJieDan(APIView):
|
||||
if jiedan_dashou_id:
|
||||
try:
|
||||
# 查询打手用户主表
|
||||
dashou_user = User.query.get(
|
||||
dashou_user = User.query.select_related('DashouProfile').get(
|
||||
UserUID=jiedan_dashou_id,
|
||||
#user_type='PlayerID'
|
||||
)
|
||||
@@ -646,7 +646,7 @@ class AdQiangZhiJieDan(APIView):
|
||||
|
||||
if shangjia_id:
|
||||
# 查询商家用户主表
|
||||
shangjia_user = User.query.get(
|
||||
shangjia_user = User.query.select_related('ShopProfile').get(
|
||||
UserUID=shangjia_id,
|
||||
#user_type='shop'
|
||||
)
|
||||
@@ -750,7 +750,7 @@ class AdJuJueTuiKuan(APIView):
|
||||
|
||||
# 6. 查询订单主表
|
||||
try:
|
||||
dingdan_obj = Order.query.get(OrderID=dingdan_id)
|
||||
dingdan_obj = Order.query.select_related('shangjia_kuozhan', 'pingtai_kuozhan').get(OrderID=dingdan_id)
|
||||
except Order.DoesNotExist:
|
||||
return Response(
|
||||
{'code': 404, 'message': '订单不存在', 'data': None},
|
||||
@@ -779,7 +779,7 @@ class AdJuJueTuiKuan(APIView):
|
||||
if jiedan_dashou_id:
|
||||
try:
|
||||
# 查询打手用户主表
|
||||
dashou_user = User.query.get(
|
||||
dashou_user = User.query.select_related('DashouProfile').get(
|
||||
UserUID=jiedan_dashou_id,
|
||||
#user_type='PlayerID'
|
||||
)
|
||||
@@ -822,7 +822,7 @@ class AdJuJueTuiKuan(APIView):
|
||||
|
||||
if shangjia_id:
|
||||
# 查询商家用户主表
|
||||
shangjia_user = User.query.get(
|
||||
shangjia_user = User.query.select_related('ShopProfile').get(
|
||||
UserUID=shangjia_id,
|
||||
#user_type='shop'
|
||||
)
|
||||
@@ -958,7 +958,7 @@ class AdTongYiTuiKuanShangJia(APIView):
|
||||
|
||||
# 7. 查询订单主表
|
||||
try:
|
||||
dingdan_obj = Order.query.get(OrderID=dingdan_id)
|
||||
dingdan_obj = Order.query.select_related('shangjia_kuozhan', 'pingtai_kuozhan').get(OrderID=dingdan_id)
|
||||
except Order.DoesNotExist:
|
||||
return Response(
|
||||
{'code': 404, 'message': '订单不存在', 'data': None},
|
||||
@@ -1010,7 +1010,7 @@ class AdTongYiTuiKuanShangJia(APIView):
|
||||
if jiedan_dashou_id:
|
||||
try:
|
||||
# 查询打手用户主表
|
||||
dashou_user = User.query.get(
|
||||
dashou_user = User.query.select_related('DashouProfile').get(
|
||||
UserUID=jiedan_dashou_id,
|
||||
#user_type='PlayerID'
|
||||
)
|
||||
@@ -1035,10 +1035,10 @@ class AdTongYiTuiKuanShangJia(APIView):
|
||||
if shangjia_id:
|
||||
try:
|
||||
# 查询商家用户主表
|
||||
shangjia_user = User.query.get(
|
||||
UserUID=shangjia_id,
|
||||
#user_type='shop'
|
||||
)
|
||||
shangjia_user = User.query.select_related('ShopProfile').get(
|
||||
UserUID=shangjia_id,
|
||||
#user_type='shop'
|
||||
)
|
||||
|
||||
# 获取商家扩展表
|
||||
shangjia_profile = shangjia_user.ShopProfile
|
||||
@@ -1228,7 +1228,7 @@ class AdTongYiTuiKuanPingTai(APIView):
|
||||
# 14. 更新打手扩展表
|
||||
if jiedan_dashou_id:
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=jiedan_dashou_id)
|
||||
dashou_user = User.query.select_related('DashouProfile').get(UserUID=jiedan_dashou_id)
|
||||
dashou_profile = dashou_user.DashouProfile
|
||||
dashou_profile.zhuangtai = 1 # 打手状态设为空闲
|
||||
dashou_profile.tuikuanliang += 1
|
||||
@@ -1239,7 +1239,7 @@ class AdTongYiTuiKuanPingTai(APIView):
|
||||
# 15. 更新老板扩展表
|
||||
if laoban_id:
|
||||
try:
|
||||
laoban_user = User.query.get(UserUID=laoban_id)
|
||||
laoban_user = User.query.select_related('BossProfile').get(UserUID=laoban_id)
|
||||
laoban_profile = laoban_user.BossProfile
|
||||
laoban_profile.alltui += 1
|
||||
laoban_profile.zonge -= jine
|
||||
@@ -1463,7 +1463,7 @@ class AdJuJueJieSuan(APIView):
|
||||
|
||||
# 8. 更新打手扩展表
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=jiedan_dashou_id)
|
||||
dashou_user = User.query.select_related('DashouProfile').get(UserUID=jiedan_dashou_id)
|
||||
dashou_profile = dashou_user.DashouProfile
|
||||
dashou_profile.zhuangtai = 1 # 打手状态设为正常
|
||||
dashou_profile.tuikuanliang += 1 # 退款订单总量+1
|
||||
@@ -1545,7 +1545,7 @@ class AdZhuanYiDaTing(APIView):
|
||||
# 如果有接单打手,更新其扩展表
|
||||
if jiedan_dashou_id:
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=jiedan_dashou_id)
|
||||
dashou_user = User.query.select_related('DashouProfile').get(UserUID=jiedan_dashou_id)
|
||||
dashou_profile = dashou_user.DashouProfile
|
||||
dashou_profile.zhuangtai = 1
|
||||
dashou_profile.tuikuanliang += 1
|
||||
@@ -1835,7 +1835,7 @@ class ZxsjghdsView(APIView):
|
||||
# 6.2 释放打手
|
||||
if dashou_id:
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=dashou_id)
|
||||
dashou_user = User.query.select_related('DashouProfile').get(UserUID=dashou_id)
|
||||
dashou_profile = dashou_user.DashouProfile
|
||||
dashou_profile.tuikuanliang = (dashou_profile.tuikuanliang or 0) + 1
|
||||
dashou_profile.zhuangtai = 1 # 空闲
|
||||
|
||||
@@ -422,11 +422,14 @@ class JiedanView(APIView):
|
||||
# 7. 更新打手扩展表(如果有打手ID和分成)
|
||||
if jiedan_dashou_id and dashou_fencheng > 0:
|
||||
# 查询打手用户
|
||||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).first()
|
||||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).select_related('DashouProfile').first()
|
||||
|
||||
if dashou_user:
|
||||
# 查询打手扩展表
|
||||
dashou_kuozhan = UserDashou.query.filter(user=dashou_user).first()
|
||||
try:
|
||||
dashou_kuozhan = dashou_user.DashouProfile
|
||||
except UserDashou.DoesNotExist:
|
||||
dashou_kuozhan = None
|
||||
|
||||
if dashou_kuozhan:
|
||||
# 更新四个金额字段
|
||||
@@ -585,7 +588,7 @@ class DingdanXiangqingView2(APIView):
|
||||
jiedan_time = ''
|
||||
tijiao_time = ''
|
||||
if jiedan_dashou_id:
|
||||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).first()
|
||||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).select_related('DashouProfile').first()
|
||||
if dashou_user:
|
||||
dashou_touxiang = dashou_user.Avatar or ''
|
||||
try:
|
||||
@@ -734,7 +737,7 @@ class JiedanView2(APIView):
|
||||
|
||||
# 9. 更新打手收益与状态
|
||||
if jiedan_dashou_id and dashou_fencheng > 0:
|
||||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).first()
|
||||
dashou_user = User.query.filter(UserUID=jiedan_dashou_id).select_related('DashouProfile').first()
|
||||
if dashou_user:
|
||||
try:
|
||||
dashou_ext = dashou_user.DashouProfile
|
||||
|
||||
@@ -193,13 +193,13 @@ def send_group_message(
|
||||
def check_user_permission(identity_type, uid, order):
|
||||
"""验证用户身份、账号状态、以及是否属于该订单"""
|
||||
try:
|
||||
user = User.query.get(UserUID=uid)
|
||||
user = User.query.select_related('DashouProfile').get(UserUID=uid)
|
||||
except User.DoesNotExist:
|
||||
return False, '用户不存在'
|
||||
|
||||
if identity_type == 'PlayerID':
|
||||
try:
|
||||
dashou = UserDashou.query.get(user=user)
|
||||
dashou = user.DashouProfile
|
||||
if dashou.zhanghaozhuangtai != 1 :
|
||||
return False, '打手账号已被封禁或状态异常'
|
||||
except UserDashou.DoesNotExist:
|
||||
@@ -516,14 +516,16 @@ class LianTongDingDanZhuangTaiPiLiangView(APIView):
|
||||
return Response({'code': 400, 'msg': 'order_ids 格式错误'})
|
||||
|
||||
uid = request.user.UserUID
|
||||
# 批量查询订单,避免循环内 N+1
|
||||
oids = [str(oid).strip() for oid in order_ids[:20] if str(oid).strip()]
|
||||
orders_map = {
|
||||
o.OrderID: o
|
||||
for o in Order.query.select_related('pingtai_kuozhan', 'shangjia_kuozhan').filter(OrderID__in=oids)
|
||||
}
|
||||
result = {}
|
||||
for oid in order_ids[:20]:
|
||||
oid = str(oid).strip()
|
||||
if not oid:
|
||||
continue
|
||||
try:
|
||||
order = Order.query.select_related('pingtai_kuozhan', 'shangjia_kuozhan').get(OrderID=oid)
|
||||
except Order.DoesNotExist:
|
||||
for oid in oids:
|
||||
order = orders_map.get(oid)
|
||||
if not order:
|
||||
continue
|
||||
for identity in ('PlayerID', 'shangjia', 'boss'):
|
||||
valid, _ = check_user_permission(identity, uid, order)
|
||||
|
||||
@@ -521,11 +521,13 @@ class ShangjiaShujuTongjiView(APIView):
|
||||
penalty_stats = None
|
||||
try:
|
||||
from orders.models import Penalty, PenaltyRecord
|
||||
from django.db.models import Q, Sum
|
||||
fakuan_pending = Penalty.query.filter(ApplicantID=yonghuid, Status__in=[1, 3]).count()
|
||||
fakuan_pending_amt = Penalty.query.filter(ApplicantID=yonghuid, Status__in=[1, 3]).aggregate(
|
||||
amt=Sum('FineAmount')
|
||||
)['amt']
|
||||
from django.db.models import Q, Sum, Count
|
||||
_fakuan_agg = Penalty.query.filter(ApplicantID=yonghuid, Status__in=[1, 3]).aggregate(
|
||||
count=Count('id'),
|
||||
amt=Sum('FineAmount'),
|
||||
)
|
||||
fakuan_pending = _fakuan_agg['count']
|
||||
fakuan_pending_amt = _fakuan_agg['amt']
|
||||
jifen_pending = PenaltyRecord.query.filter(
|
||||
ApplicantID=yonghuid,
|
||||
).filter(Q(ApplyStatus=0) | Q(ApplyStatus=3)).count()
|
||||
@@ -1204,7 +1206,7 @@ class ShangjiaTuikuanShenqingView(APIView):
|
||||
try:
|
||||
dashou_main = User.query.filter(
|
||||
UserUID=dingdan.PlayerID
|
||||
).first()
|
||||
).select_related('DashouProfile').first()
|
||||
if dashou_main and hasattr(dashou_main, 'DashouProfile'):
|
||||
dashou_profile = dashou_main.DashouProfile
|
||||
dashou_profile.zhuangtai = 1
|
||||
@@ -1285,7 +1287,7 @@ class ShangjiaChufaShenqingView(APIView):
|
||||
with transaction.atomic():
|
||||
# 验证打手身份
|
||||
try:
|
||||
dashou_user = User.query.get(UserUID=dashou_id)
|
||||
dashou_user = User.query.select_related('DashouProfile').get(UserUID=dashou_id)
|
||||
dashou = dashou_user.DashouProfile
|
||||
except User.DoesNotExist:
|
||||
return Response({
|
||||
@@ -1367,13 +1369,16 @@ class ShangjiaChufaShenqingView(APIView):
|
||||
|
||||
# 🔴【新增】保存处罚图片到数据库
|
||||
if chufa_tupian_urls and isinstance(chufa_tupian_urls, list):
|
||||
for tupian_url in chufa_tupian_urls:
|
||||
if tupian_url and tupian_url.strip():
|
||||
PenaltyEvidenceImage.query.create(
|
||||
_valid_urls = [u.strip() for u in chufa_tupian_urls if u and u.strip()]
|
||||
if _valid_urls:
|
||||
PenaltyEvidenceImage.objects.bulk_create([
|
||||
PenaltyEvidenceImage(
|
||||
OrderID=dingdan_id,
|
||||
UserID=current_user.UserUID,
|
||||
ImageURL=tupian_url
|
||||
ImageURL=url,
|
||||
)
|
||||
for url in _valid_urls
|
||||
])
|
||||
|
||||
# 更新商家订单扩展表的处罚相关字段
|
||||
shangjia_kuozhan.PenaltyReason = chufa_liyou
|
||||
|
||||
@@ -188,13 +188,15 @@ class ShangjiaFakuanApplyView(APIView):
|
||||
),
|
||||
ShopStaffUserID=staff_kefu_id,
|
||||
)
|
||||
for url in evidence_urls:
|
||||
PenaltyAppealImage.query.create(
|
||||
PenaltyAppealImage.objects.bulk_create([
|
||||
PenaltyAppealImage(
|
||||
Penalty=fadan,
|
||||
PenalizedUserID=dashou_id,
|
||||
ImageURL=url,
|
||||
Purpose=1,
|
||||
)
|
||||
for url in evidence_urls
|
||||
])
|
||||
lock_penalty_bonus(fadan)
|
||||
logger.info(f"商家{shangjia_id}对订单{dingdan_id}打手{dashou_id}提交罚款申请(平台审核),金额{fakuanjine}")
|
||||
return Response({'code': 0, 'msg': '罚款申请已提交,等待平台审核', 'data': {'fadan_id': fadan.id}})
|
||||
@@ -362,16 +364,17 @@ class ShangjiaFakuaiXiugaiView(APIView):
|
||||
existing_count = PenaltyAppealImage.query.filter(Penalty=fadan, Purpose=1).count()
|
||||
if existing_count + len(add_urls) > 9:
|
||||
return Response({'code': 400, 'msg': '证据图片最多9张'})
|
||||
for url in add_urls:
|
||||
url = str(url).strip()
|
||||
if not url:
|
||||
continue
|
||||
PenaltyAppealImage.query.create(
|
||||
Penalty=fadan,
|
||||
PenalizedUserID=fadan.PenalizedUserID,
|
||||
ImageURL=url,
|
||||
Purpose=1,
|
||||
)
|
||||
_valid_add_urls = [str(u).strip() for u in add_urls if str(u).strip()]
|
||||
if _valid_add_urls:
|
||||
PenaltyAppealImage.objects.bulk_create([
|
||||
PenaltyAppealImage(
|
||||
Penalty=fadan,
|
||||
PenalizedUserID=fadan.PenalizedUserID,
|
||||
ImageURL=url,
|
||||
Purpose=1,
|
||||
)
|
||||
for url in _valid_add_urls
|
||||
])
|
||||
logger.info(
|
||||
f"罚单{fadan.id}证据图变更:新增{len(add_urls)}张,删除{len(remove_ids)}张"
|
||||
)
|
||||
|
||||
@@ -204,7 +204,9 @@ class WechatPayNotifyView(APIView):
|
||||
|
||||
# 锁定订单防止并发
|
||||
try:
|
||||
dingdan = Order.query.select_for_update().filter(OrderID=out_trade_no).first()
|
||||
dingdan = Order.query.select_for_update().select_related(
|
||||
'pingtai_kuozhan', 'shangjia_kuozhan'
|
||||
).filter(OrderID=out_trade_no).first()
|
||||
except Exception as e:
|
||||
logger.error(f"查询订单异常: {e}")
|
||||
raise
|
||||
@@ -263,7 +265,7 @@ class WechatPayNotifyView(APIView):
|
||||
if hasattr(dingdan, 'pingtai_kuozhan'):
|
||||
laoban_id = dingdan.pingtai_kuozhan.BossID
|
||||
if laoban_id:
|
||||
user_main = User.query.filter(UserUID=laoban_id).first()
|
||||
user_main = User.query.filter(UserUID=laoban_id).select_related('BossProfile').first()
|
||||
if user_main and hasattr(user_main, 'BossProfile'):
|
||||
boss = user_main.BossProfile
|
||||
boss.zonge = (boss.zonge or 0) + (dingdan.Amount or 0)
|
||||
@@ -537,7 +539,7 @@ class PaymentVerifyView(APIView):
|
||||
# 更新老板扩展表
|
||||
laoban_id = dingdan.pingtai_kuozhan.BossID if hasattr(dingdan, 'pingtai_kuozhan') else None
|
||||
if laoban_id:
|
||||
user_main = User.query.filter(UserUID=laoban_id).first()
|
||||
user_main = User.query.filter(UserUID=laoban_id).select_related('BossProfile').first()
|
||||
if user_main and hasattr(user_main, 'BossProfile'):
|
||||
boss = user_main.BossProfile
|
||||
boss.zonge = (boss.zonge or 0) + (dingdan.Amount or 0)
|
||||
@@ -709,13 +711,16 @@ class CreateOrderView(APIView):
|
||||
zhiding_user = User.query.filter(
|
||||
UserUID=zhiding,
|
||||
#user_type='PlayerID'
|
||||
).first()
|
||||
).select_related('DashouProfile').first()
|
||||
|
||||
if not zhiding_user:
|
||||
return Response({'code': 7, 'msg': '指定打手不存在', 'data': None})
|
||||
|
||||
# 查询打手扩展表
|
||||
dashou_profile = UserDashou.query.filter(user=zhiding_user).first()
|
||||
try:
|
||||
dashou_profile = zhiding_user.DashouProfile
|
||||
except UserDashou.DoesNotExist:
|
||||
dashou_profile = None
|
||||
|
||||
if not dashou_profile:
|
||||
return Response({'code': 8, 'msg': '指定用户不存在或已封禁', 'data': None})
|
||||
|
||||
Reference in New Issue
Block a user