Home > Back-end >  New objects are made every time
New objects are made every time

Time:03-25

I made a single function for register and login with mobile and otp. The register part is in the else part of the function, and the if part is the login function. Every time I log in with the already registered number, it makes a new object in the database, and I don't want that. I want to just update the otp part from when the number was registered in the database.

views.py

class RegistrationAPIView(APIView):
    permission_classes = (AllowAny,)
    serializer_class = ProfileSerializer
    def post(self, request):
        mobile = request.data['mobile']
        data = Profile.objects.filter(mobile = mobile).first()
        if data:
            serializer = self.serializer_class(data=request.data)
            mobile = request.data['mobile']
            if serializer.is_valid(raise_exception=True):
                instance = serializer.save()
                content = {'mobile': instance.mobile, 'otp': instance.otp}
                mobile = instance.mobile
                otp = instance.otp
                print("Success")
                send_otp(mobile,otp)
                return Response(content, status=status.HTTP_201_CREATED)
            else:
                return Response({"Error": "Login in Failed"}, status=status.HTTP_400_BAD_REQUEST)
        else:
            serializer = self.serializer_class(data=request.data)
            mobile = request.data['mobile']
            if serializer.is_valid(raise_exception=True):
                instance = serializer.save()
                content = {'mobile': instance.mobile, 'otp': instance.otp}
                mobile = instance.mobile
                otp = instance.otp
                send_otp(mobile,otp)
                return Response(content, status=status.HTTP_201_CREATED)
            else:
                return Response({"Error": "Sign Up Failed"}, status=status.HTTP_400_BAD_REQUEST)

serializers.py

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ['mobile']
    def create(self, validated_data):
        
            instance = self.Meta.model(**validated_data)
            global totp
            secret = pyotp.random_base32()
            totp = pyotp.TOTP(secret, interval=300)
            otp = totp.now()
            instance.otp = str(random.randint(1000 , 9999))
            instance.save()
            return instance

models.py

'''

class Profile(models.Model):
   mobile = models.CharField(max_length=20)
   otp = models.CharField(max_length=6)

'''

CodePudding user response:

I'm assuming here that you're using DRF Serializers. If that's the case, note from the documentation that :

Calling .save() will either create a new instance, or update an existing instance, depending on if an existing instance was passed when instantiating the serializer class:

# .save() will create a new instance.
serializer = CommentSerializer(data=data)

# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)

As an aside, you probably want to do a get_or_create or create_or_update with defaults instead of having the if/else clause.

CodePudding user response:

Option A: First thing first. If there is only and only one mobile number for each Profile you should add a unique constraint for your Profile model as well. Something like:

class Profile(models.Model):
   mobile = models.CharField(max_length=20, unique=True)
   otp = models.CharField(max_length=6)

Do not forget to make migration and migrate these new changes to your database (also note that there might be some duplicate records in Profile table so if you're not on production server first delete all of your records and then make this migration).

And then make this change to your serializer's create method:

def create(self, validated_data):
    global totp
    secret = pyotp.random_base32()
    totp = pyotp.TOTP(secret, interval=300)
    otp = totp.now()
    instance = self.Meta.model.objects.update_or_create(**validated_data, defualts=dict(otp=str(random.randint(1000 , 9999))))[0]
    return instance

with update_or_create now you're sure that if the record with specific mobile exists you will update that and if not you will create new one.

Option B: But if you don't want to make this change to your database for any reason you can just simply do this:

def create(self, validated_data):
        global totp
        secret = pyotp.random_base32()
        totp = pyotp.TOTP(secret, interval=300)
        otp = totp.now()
        
        if self.Meta.model.objects.filter(**validated_data).exists():
            instance = self.Meta.model.objects.filter(**validated_data).last()          
            instance.otp = str(random.randint(1000 , 9999))
            instance.save()
        else:
            instance = self.Meta.model(**validated_data)
            instance.otp = str(random.randint(1000 , 9999))
            instance.save()
        return instance

Note that there might be multiple records in your table with same mobile number as long as there isn't any constraint on that model and here we are only updating latest record in your Profile table. I hope these two options solve your problem.

  • Related