Каждый раз создаются новые объекты

Я сделал одну функцию для регистрации и входа с помощью мобильного и otp. Регистрационная часть находится в else части функции, а if часть - это функция входа. Каждый раз, когда я вхожу в систему с уже зарегистрированным номером, создается новый объект в базе данных, а я этого не хочу. Я хочу просто обновить часть otp с того момента, когда номер был зарегистрирован в базе данных.

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

Я предполагаю, что вы используете DRF Serializers. Если это так, обратите внимание из документации, что :

Вызов .save() либо создаст новый экземпляр, либо обновит существующий, в зависимости от того, был ли передан существующий экземпляр при инстанцировании класса сериализатора:

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

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

В качестве дополнения, вы, вероятно, хотите сделать get_or_create или create_or_update с defaults вместо того, чтобы использовать предложение if/else.

Вариант A: Прежде всего. Если для каждого профиля существует только и исключительно один номер мобильного телефона, вы должны добавить уникальное ограничение и для модели профиля. Что-то вроде:

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

Не забудьте сделать миграцию и перенести эти новые изменения в вашу базу данных (также обратите внимание, что в таблице Profile могут быть некоторые дублирующиеся записи, поэтому если вы не на рабочем сервере, сначала удалите все записи, а затем сделайте миграцию).

А затем внесите следующее изменение в метод create вашего сериализатора:

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

с update_or_create теперь вы уверены, что если запись с определенным мобильным телефоном существует, то вы обновите ее, а если нет, то создадите новую.

Вариант B: Но если вы по каким-либо причинам не хотите вносить это изменение в вашу базу данных, вы можете просто сделать следующее:

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 = Profile.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

Обратите внимание, что в вашей таблице может быть несколько записей с одним и тем же номером мобильного телефона, если на эту модель не наложено никаких ограничений. Надеюсь, эти два варианта решат вашу проблему.

Вернуться на верх