在 django allauth 中处理重复的电子邮件地址

Handling duplicate email address in django allauth

我想做什么?

我正在尝试按照以下步骤避免重复的电子邮件地址:

  1. 在用户从社交帐户登录到我的网站之前,我会检查电子邮件地址是否已经存在。
  2. 如果否,则登录用户,否则检查以下步骤。

    • 检查注册用户的提供商是否与尝试登录的用户匹配。

    • 如果否,则不允许用户登录,否则登录用户。

有什么问题吗?

我收到以下错误:

错误: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.

编辑:

由于 FacebookTwitterLinkedin 允许用户选择使用他们的 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