在 django allauth 中处理重复的电子邮件地址
Handling duplicate email address in django allauth
我想做什么?
我正在尝试按照以下步骤避免重复的电子邮件地址:
- 在用户从社交帐户登录到我的网站之前,我会检查电子邮件地址是否已经存在。
如果否,则登录用户,否则检查以下步骤。
检查注册用户的提供商是否与尝试登录的用户匹配。
如果否,则不允许用户登录,否则登录用户。
有什么问题吗?
我收到以下错误:
错误:AttributeError at /accounts/twitter/login/callback/
'QuerySet' object has no attribute 'profile'
我的代码:
views.py:
@receiver(pre_social_login)
def handleDuplicateEmail(sender, request, sociallogin, **kwargs):
if sociallogin.account.provider == 'facebook' or sociallogin.account.provider == 'twitter':
email_address = sociallogin.account.extra_data['email'] # get email address from fb or twitter social account.
else:
email_address = sociallogin.account.extra_data['email-address'] # Get email from linkedin social account.
users = User.objects.all().filter(email=email_address) # This line is problematic
if users:
if not (users.profile.provider == sociallogin.account.provider): # Different user is trying to login with already existing user's email address.
response = 'Your social account email address is already registered to some account. Please choose a different one.'
raise ImmediateHttpResponse(render(request, 'index.html', {'type': True, 'response': response})) # redirect to index template with error message.
models.py:
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
provider = models.CharField(max_length=256, blank=True, null=True) # for storing name of provider used to login with.
编辑:
由于 Facebook、Twitter 和 Linkedin 允许用户选择使用他们的 phone 号码或电子邮件地址,如果他们选择 phone 号码,那么用户将没有与之关联的电子邮件地址来处理这种情况,我已经更新了我的代码,如下所示:
if sociallogin.account.provider == 'facebook' or sociallogin.account.provider == 'twitter':
try:
email_address = sociallogin.account.extra_data['email']
except:
email_address = None # If social account was created on phone number for facebook & twitter
else:
try:
email_address = sociallogin.account.extra_data['email-address']
except:
email_address = None # If social account was created on phone number or linkedin
if email_address:
users = User.objects.all().filter(email=email_address)
if users.exists():
...
else:
response = 'You have not provided an email address in your social account. Please register as local user or use a different social account.'
raise ImmediateHttpResponse(render(request, 'index.html', {'type': True, 'response': response}))
users = User.objects.all().filter(email=email_address)
return 是一个 QuerySet
所以你不能只调用 .profile
它。理论上,此查询可以 return 多个 User
对象。但它也可能包含 0 个对象(更有可能)。
所以你需要处理这些情况:
if users.exists():
user = users.first() # assuming there will always only be one user
if not user.profile.provider == sociallogin.account.provider:
etc...
或
if users.exists():
for user in users:
if not user.profile.provider == sociallogin.account.provider:
etc...
break
我想做什么?
我正在尝试按照以下步骤避免重复的电子邮件地址:
- 在用户从社交帐户登录到我的网站之前,我会检查电子邮件地址是否已经存在。
如果否,则登录用户,否则检查以下步骤。
检查注册用户的提供商是否与尝试登录的用户匹配。
如果否,则不允许用户登录,否则登录用户。
有什么问题吗?
我收到以下错误:
错误:AttributeError at /accounts/twitter/login/callback/
'QuerySet' object has no attribute 'profile'
我的代码:
views.py:
@receiver(pre_social_login)
def handleDuplicateEmail(sender, request, sociallogin, **kwargs):
if sociallogin.account.provider == 'facebook' or sociallogin.account.provider == 'twitter':
email_address = sociallogin.account.extra_data['email'] # get email address from fb or twitter social account.
else:
email_address = sociallogin.account.extra_data['email-address'] # Get email from linkedin social account.
users = User.objects.all().filter(email=email_address) # This line is problematic
if users:
if not (users.profile.provider == sociallogin.account.provider): # Different user is trying to login with already existing user's email address.
response = 'Your social account email address is already registered to some account. Please choose a different one.'
raise ImmediateHttpResponse(render(request, 'index.html', {'type': True, 'response': response})) # redirect to index template with error message.
models.py:
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
provider = models.CharField(max_length=256, blank=True, null=True) # for storing name of provider used to login with.
编辑:
由于 Facebook、Twitter 和 Linkedin 允许用户选择使用他们的 phone 号码或电子邮件地址,如果他们选择 phone 号码,那么用户将没有与之关联的电子邮件地址来处理这种情况,我已经更新了我的代码,如下所示:
if sociallogin.account.provider == 'facebook' or sociallogin.account.provider == 'twitter':
try:
email_address = sociallogin.account.extra_data['email']
except:
email_address = None # If social account was created on phone number for facebook & twitter
else:
try:
email_address = sociallogin.account.extra_data['email-address']
except:
email_address = None # If social account was created on phone number or linkedin
if email_address:
users = User.objects.all().filter(email=email_address)
if users.exists():
...
else:
response = 'You have not provided an email address in your social account. Please register as local user or use a different social account.'
raise ImmediateHttpResponse(render(request, 'index.html', {'type': True, 'response': response}))
users = User.objects.all().filter(email=email_address)
return 是一个 QuerySet
所以你不能只调用 .profile
它。理论上,此查询可以 return 多个 User
对象。但它也可能包含 0 个对象(更有可能)。
所以你需要处理这些情况:
if users.exists():
user = users.first() # assuming there will always only be one user
if not user.profile.provider == sociallogin.account.provider:
etc...
或
if users.exists():
for user in users:
if not user.profile.provider == sociallogin.account.provider:
etc...
break