# -*- coding: utf-8 -*- from django.db import IntegrityError, transaction from django.utils import timezone from django_logit import logit from django_response import response from django.db.models import Q from account.models import UserInfo from sales.models import LotteryCampaignInfo, LotteryEntryInfo from utils.error.errno_utils import LotteryStatusCode, UserStatusCode def join_lottery(user, serial_no, model_id='', campaign_id='', submit_pk='', phone='', model_name=''): """ 写入抽奖名额(幂等) 返回 (entry, campaign, is_new): · 没有进行中的活动 → (None, None, False) · 已有名额 → (entry, campaign, False) · 首次参与 → (entry, campaign, True) """ serial_no = (serial_no or '').strip() campaign = LotteryCampaignInfo.objects.get(status=True, campaign_id=campaign_id) if not campaign: return None, None # 嵌套 atomic 生成 savepoint:并发插入冲突后还能继续查询 with transaction.atomic(): entry, created = LotteryEntryInfo.objects.get_or_create( campaign_id=campaign.campaign_id, serial_no=serial_no, submit_pk=submit_pk, title=campaign.title, phone=phone, user_id=user.user_id, model_id=model_id, model_name=model_name, ) return entry, campaign @logit(res=True) @transaction.atomic def lottery_join_api(request): """抽奖参与接口:写入名额""" user_id = request.POST.get('user_id', '') serial_no = request.POST.get('serial_no') model_id = request.POST.get('model_id') campaign_id = request.POST.get('campaign_id', '') submit_pk = request.POST.get('submit_pk', '') phone = request.POST.get('phone', '') model_name = request.POST.get('model_name', '') try: user = UserInfo.objects.select_for_update().get(user_id=user_id) except UserInfo.DoesNotExist: return response(UserStatusCode.USER_NOT_FOUND) # TODO 安全:应校验该序列号确实绑定在当前用户名下,防止传入他人序列号刷名额 entry, campaign = join_lottery(user, serial_no, model_id, campaign_id, submit_pk, phone, model_name) if not campaign: return response(LotteryStatusCode.CAMPAIGN_NOT_FOUND) return response(200, data={ 'campaign': serialize_campaign(campaign), 'entry': serialize_entry(entry), })