Reputation: 10116
What I am trying to do ?
I am trying to avoid duplicate email address by following these steps:
If no then login the user otherwise check the below steps.
Check to see if the provider of registered user match the user trying to login.
If no then don't allow user to login otherwise login the user.
What is the problem ?
I get the following error:
Error:AttributeError at /accounts/twitter/login/callback/
'QuerySet' object has no attribute 'profile'
My Code:
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.
Edit:
Since Facebook, Twitter and Linkedin give users a choice to login with their phone number or email address and if they choose phone number then in that cause users won't have an email address associated with them to handle this situation I have updated my code like so:
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}))
Upvotes: 2
Views: 3483
Reputation: 20692
users = User.objects.all().filter(email=email_address)
returns a QuerySet
so you can't just call .profile
on it. In theory this query could return multiple User
objects. But it could also contain 0 objects (which is more likely).
So you need to handle these cases:
if users.exists():
user = users.first() # assuming there will always only be one user
if not user.profile.provider == sociallogin.account.provider:
etc...
or
if users.exists():
for user in users:
if not user.profile.provider == sociallogin.account.provider:
etc...
break
Upvotes: 1