Reputation: 339
I have 2 models
class User(models.Model):
email = models.CharField(max_length = 100)
password = models.CharField(max_length = 100)
class Authentication(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
token = models.CharField(max_length =50, null = True)
Here is the code I use for login in views.py
from user.models import User, Authentication
import uuid
from django.db.utils import IntegrityError
user = User.objects.get(pk = request.user.id)
token = uuid.uuid4().hex
try:
Authentication.objects.create(user = user, token = token)
except IntegrityError:
user.authentication.token = token
user.authentication.save()
return JsonResponse({'token':token})
The problem I meet here is everytime a user login, I will generate a new token and save in the database. The error appears at the line
user.authentication.save()
The error is: django.db.utils.IntegrityError: (1062, "Duplicate entry '30' for key 'user_id' ") The 30 is the user_id existed in Authentication models when login in the second time ( the first time login is always succeed). I solved this problem by using these codes:
except IntegrityError:
au = Authentication.objects.get(user = user)
au.token = token
au.save()
But I dont know why i got this bug. I used to do the first approach many times but not got no bugs at all. Anyone has faced to this problem can show me the way to solve this? Thank you
Upvotes: 1
Views: 803
Reputation: 1103
The problem is that you are trying to create a new token to a user who already have one, and since you've defined a OneToOneField
it is not possible. I suggest you to try the get_or_create()
instead of create()
method.
Alternatively, you can modify the create method:
try:
auth = Authentication.objects.create(user = request.user)
except Exception as e:
#do something
return JsonResponse({'token': auth.token})
In models.py
from user.managers import MyManager
class Authentication(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
token = models.CharField(max_length =50, null = True)
objects = MyManager()
Then create a file 'managers.py' and put this in it:
from django.db import models
import uuid
class MyManager(models.Manager):
def create(self, user):
token = uuid.uuid4().hex
if user.authentication:
user.authentication.token = token
user.authentication.save()
return user.authentication
else:
auth = self.model(user=user, token=token)
auth.save(using=self._db)
return auth
Now if you use Authentication.objects.create(user=request.user)
the create
method in MyManager
will be invoked. This also helps to separate token generation from views.py
Cheers!
Upvotes: 1