Django: "Не удается преобразовать ключевое слово 'email' в поле. Варианты: created_at, expires_at, id, otp, user, user_id".

Я пытаюсь проверить OTP, который был отправлен пользователю при регистрации. У меня есть отдельная модель для otp, которая имеет отношение OneToOne с пользователем

Otp Model

class Verify(models.Model):
user = models.ForeignKey(
    User, on_delete=models.CASCADE, related_name="userverify", blank=False, null=True)
otp = IntegerRangeField(
    min_value=111111, max_value=999999, blank=True, null=True)
created_at = models.DateTimeField(
    _("created at"), auto_now=False, auto_now_add=True, blank=False)
expires_at = models.TimeField(null=True)

VerifySerializer: Я не указываю модель, потому что она нужна мне только для проверки достоверности входных данных, хотя я думаю, что это может быть проблемой

class VerifySerializerBase(serializers.Serializer):
   email = serializers.EmailField()
   otp = serializers.CharField()

представление Verify_Email принимает email и значение otp для проверки email

Как я пытаюсь проверить otp

class Verify_Email(APIView):
    def post(self, request):
        try:
            data = request.data
            serializer = VerifySerializerBase(data=data)
            if serializer.is_valid():
                email = serializer.data['email']
                otp = serializer.data['otp']
                verify = Verify.objects.filter(email=email, otp=otp)
                user = User.objects.filter(email=email)

                if not user[0].exists():
                    return Response({
                        'message': "A user with this email was not found"
                    }, status=status.HTTP_400_BAD_REQUEST)
                elif user[0].is_active:
                    return Response({
                        'message': "This email has already been verified"
                    }, status=status.HTTP_400_BAD_REQUEST)

                elif verify[0].exists():
                    if verify[0].expires_at >= datetime.now():
                        return Response({
                            'message': "This OTP has expired, please request another one"
                        }, status=status.HTTP_400_BAD_REQUEST)
                    elif verify[0].otp != otp:
                        return Response({
                            'message': "This OTP is invalid"
                        }, status=status.HTTP_400_BAD_REQUEST)
                    else:
                        verify[0].delete()
                        user[0].is_active = True
                        user[0].save()
                        return Response({
                            'message': "Email has been verified"
                        }, status=status.HTTP_200_OK)
                return Response({
                    'message': "Something is wrong"
                }, status=status.HTTP_400_BAD_REQUEST)

            return Response({
                'message': "Something is wrong"
            }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            return Response(str(e), status=status.HTTP_404_NOT_FOUND, template_name=None, content_type=None)

и при тестировании я получаю

"Cannot resolve keyword 'email' into field. Choices are: created_at, expires_at, id, otp, user, user_id"

Из того, что я понимаю, я думаю, что это говорит мне, что я проверяю поля, которых нет в полях модели OTP, но я не думаю, что я делаю это?

Ошибка относится к моделям, а не к сериализатору. Эта строка подразумевает, что модель Verify имеет поле email, поскольку вы строите запрос на этом поле:

verify = Verify.objects.filter(email=email, otp=otp)

Возможно, вы имели в виду запрос по пользователю, что предполагает замену следующей строки следующим образом:

user = User.objects.get(email=email)
verify = Verify.objects.filter(user=user, otp=otp)

я думаю, что ответ Даниэля правильный, но немного неточный вместо этого используйте

 user = User.objects.get(email=email)

можно использовать

 user = User.objects.filter(email=email).first()
 if user is None:
   raise Exception("")

Это лучше, потому что вы можете использовать свой собственный обработчик ошибок другая проблема возникает в вашей модели, если у вас есть дублированный или более otp код в этой ситуации ваш набор запросов выглядит как

verify = Verify.objects.filter(user=user, otp=otp)

возвращает список проверяемых объектов, очевидно, что это не лучшее решение. измените модель следующим образом

 class Verify(models.Model):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, 
        related_name="userverify", 
        blank=False, 
        null=True
    )
    otp = IntegerRangeField(
        min_value=111111, max_value=999999, blank=True, null=True
    )
    created_at = models.DateTimeField(
        _("created at"), auto_now=False, auto_now_add=True, blank=False
    )
    expires_at = models.TimeField(null=True)
    is_active = models.BooleanField(default=True)

теперь используйте

 verify = Verify.objects.filter(user=user, otp=otp, is_active=True)

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