I am using djangorestframework-simplejwt
for authentication. My use case requires me to use OTP instead of passwords.
To store OTPs, I have created the following model:
class OneTimePassword(models.Model):
otp = models.IntegerField()
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
User model:
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
country_code = models.IntegerField(default=91, max_length=3)
mobile = models.IntegerField(max_length=11, unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['mobile']
objects = CustomUserManager()
def __str__(self):
return f"{self.email},{self.mobile}"
My plan is:
mobile
to /api/generate_otp/
endpointOneTimePassword
model. (the user is determined from mobile number)api/token/obtain/
endpoint, OTP and mobile number is posted.I am facing difficulty in step 2, i.e. I am not able to update the value of OTP in OneTimePassword Model through the user.
I have tried the following approach:
class GenerateOTPMobileView(APIView):
permission_classes = ()
def post(self, request,):
mobile = request.data.get("mobile")
user = User.objects.get(mobile=mobile)
random_otp = randint(10000, 99999)
if user:
user.onetimepassword_set.otp = random_otp # This is not working
...
# send OTP through third party API
...
return Response({"success": "OTP sent to mobile number"},)
else:
return Response({"error": "Wrong Credentials"}, status=status.HTTP_400_BAD_REQUEST)
You're trying to set a property on the many side of a relationship and it doesn't work that way. Basically, you're just setting a property on the manager and the manager just like any other well behaved python object, will just set this property on itself - but it doesn't do anything useful.
Instead, you should either create()
a new OTP or update()
a specific OTP.
Remember your data model looks like this:
user:
- otp1
- otp2
- otp3
etc.
So there is not "one OTP for one user". For that you need a OneToOneField.