Django-allauth:如何设置SocialLogin手机号可选以避免登录报错?
问题根源
你在settings.py的ACCOUNT_SIGNUP_FIELDS中将phone*设为全局必填字段,但Google第三方登录返回的用户信息中无公开手机号,导致系统在校验时触发KeyError 'phone'。
解决方案
方案一:区分普通注册与SocialAuth注册的表单规则
这种方式既能保留普通注册时手机号必填的要求,又允许SocialAuth登录时跳过手机号校验:
- 修改全局字段配置
去掉ACCOUNT_SIGNUP_FIELDS中phone的星号,将其设为全局可选:ACCOUNT_LOGIN_METHODS = {"phone", "email", "username"} ACCOUNT_SIGNUP_FIELDS = [ "phone", "email*", "username*", "password1", "password2" ] - 自定义普通注册表单
在你的app目录下创建forms.py,强制普通注册时手机号必填:from allauth.account.forms import SignupForm from django import forms class CustomSignupForm(SignupForm): phone = forms.CharField(required=True, label="手机号") def save(self, request): user = super().save(request) user.phone = self.cleaned_data['phone'] user.save() return user - 指定自定义表单
在settings.py中配置使用自定义注册表单:ACCOUNT_FORMS = { 'signup': 'your_app.forms.CustomSignupForm', }
方案二:自定义SocialAccount适配器
通过重写适配器逻辑,直接让SocialAuth登录流程跳过手机号必填校验:
- 创建自定义适配器
在你的app目录下创建adapter.py:from allauth.socialaccount.adapter import DefaultSocialAccountAdapter class CustomSocialAccountAdapter(DefaultSocialAccountAdapter): def get_signup_form(self, request, sociallogin): from allauth.account.forms import SignupForm form = SignupForm(request.POST) # 移除手机号的必填限制 form.fields['phone'].required = False return form def save_user(self, request, sociallogin, form=None): user = super().save_user(request, sociallogin, form) # 这里可保留你的手机号更新逻辑,注意增加空值判断 phone = getattr(user, 'phone', None) if phone: sociallogin.account.extra_data['phone'] = phone sociallogin.account.save() return user - 配置使用自定义适配器
在settings.py中指定适配器路径:SOCIALACCOUNT_ADAPTER = 'your_app.adapter.CustomSocialAccountAdapter'
额外注意:修复信号接收器的空值处理
确保你的自定义信号接收器在无手机号时不报错,增加空值判断:
from django.db.models.signals import post_save from allauth.socialaccount.models import SocialAccount from django.dispatch import receiver @receiver(post_save, sender=SocialAccount) def update_social_account_phone(sender, instance, created, **kwargs): if created: # 先判断用户是否有手机号,避免触发KeyError phone = getattr(instance.user, 'phone', None) if phone: instance.extra_data['phone'] = phone instance.save()
内容的提问来源于stack exchange,提问作者arunkumar
相关产品推荐
相关产品推荐

