fix: 微信登录并发注册撞唯一键时正确回落已有用户

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-09 01:12:46 +08:00
parent d5fbc08364
commit 5754f6a509

View File

@@ -1,5 +1,5 @@
"""用户所属俱乐部解析。"""
from django.db import IntegrityError
from django.db import IntegrityError, transaction
from jituan.constants import CLUB_ID_DEFAULT
from jituan.models import UserWxOpenid
@@ -41,27 +41,52 @@ def resolve_invite_party_club(user, request_club_id=None):
return None
def find_user_by_wx_openid(club_id, openid):
"""按俱乐部 openid 绑定或 legacy OpenID/UserName 定位用户"""
def _user_querysets():
"""兼容 gvsdsdk User.query 与 Django User.objects"""
from users.business_models import User
if club_id and openid:
seen = set()
for qs in (getattr(User, 'objects', None), getattr(User, 'query', None)):
if qs is None or id(qs) in seen:
continue
seen.add(id(qs))
yield qs
def find_user_by_wx_openid(club_id, openid):
"""按俱乐部 openid 绑定或 legacy UserName/OpenID 定位用户。"""
from users.business_models import User
openid = (openid or '').strip()
if not openid:
return None
if club_id:
binding = UserWxOpenid.query.filter(club_id=club_id, openid=openid).first()
if binding:
user = User.query.filter(UserUID=binding.yonghuid).first()
user = User.objects.filter(UserUID=binding.yonghuid).first()
if not user:
user = User.objects.filter(UserUID=binding.yonghuid).first()
user = User.query.filter(UserUID=binding.yonghuid).first()
if user:
return user
user = User.query.filter(OpenID=openid).first()
if not user:
user = User.objects.filter(OpenID=openid).first()
if not user:
user = User.query.filter(UserName=openid).first()
if not user:
user = User.objects.filter(UserName=openid).first()
return user
binding_any = UserWxOpenid.query.filter(openid=openid).order_by('id').first()
if binding_any:
user = User.objects.filter(UserUID=binding_any.yonghuid).first()
if not user:
user = User.query.filter(UserUID=binding_any.yonghuid).first()
if user:
return user
# 星之界等用户常 UserName=openid 且 OpenID 为空,优先按 UserName 查
for manager in _user_querysets():
user = manager.filter(UserName=openid).first()
if user:
return user
user = manager.filter(OpenID=openid).first()
if user:
return user
return None
def ensure_wx_openid_binding(club_id, openid, user, unionid=''):
@@ -95,23 +120,29 @@ def resolve_or_create_wx_user(club_id, openid, generate_uid, unionid=''):
import uuid
from users.business_models import User
openid = (openid or '').strip()
if not openid:
raise ValueError('openid 不能为空')
user = find_user_by_wx_openid(club_id, openid)
if user:
ensure_wx_openid_binding(club_id, openid, user, unionid)
return user, False
try:
user = User(
UserUUID=uuid.uuid4().bytes,
UserUID=generate_uid(),
UserName=openid,
OpenID=openid if club_id == CLUB_ID_DEFAULT else None,
UnionID=unionid or None,
ClubID='',
)
user.save()
ensure_wx_openid_binding(club_id, openid, user, unionid)
return user, True
# 嵌套 savepoint并发注册撞唯一键时只回滚创建不污染外层 atomic
with transaction.atomic():
user = User(
UserUUID=uuid.uuid4().bytes,
UserUID=generate_uid(),
UserName=openid,
OpenID=openid if club_id == CLUB_ID_DEFAULT else None,
UnionID=unionid or None,
ClubID='',
)
user.save()
ensure_wx_openid_binding(club_id, openid, user, unionid)
return user, True
except IntegrityError:
user = find_user_by_wx_openid(club_id, openid)
if not user: