From 5754f6a5096237753932edce496ea096cfff4c04 Mon Sep 17 00:00:00 2001 From: XingQue Date: Thu, 9 Jul 2026 01:12:46 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BE=AE=E4=BF=A1=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E6=B3=A8=E5=86=8C=E6=92=9E=E5=94=AF=E4=B8=80?= =?UTF-8?q?=E9=94=AE=E6=97=B6=E6=AD=A3=E7=A1=AE=E5=9B=9E=E8=90=BD=E5=B7=B2?= =?UTF-8?q?=E6=9C=89=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- jituan/services/club_user.py | 81 +++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/jituan/services/club_user.py b/jituan/services/club_user.py index 9c2ffcd..34db884 100644 --- a/jituan/services/club_user.py +++ b/jituan/services/club_user.py @@ -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: