Как обновить модель внутри исключения функции представления и заставить транзакцию зафиксироваться в базе данных?

Мы пытаемся создать модель для контроля количества попыток доступа пользователя, а затем сделать вызов функции, которая может выбросить исключение, если, например, учетные данные не действительны. Если есть исключение, обновляем модель, увеличивая количество попыток на единицу, в противном случае обновляем модель другим способом. Каждый раз, когда мы находимся в ветке исключений, модель не создается и не обновляется. Мы пробовали использовать

    s1 = transaction.savepoint()
    transaction.savepoint_commit(s1) 
and @transaction.non_atomic_requests

но результат все равно отбрасывается. Нет никакого способа избежать логики исключения. Версия Django: Django==2.2.24

access_attempt.py

from django.db import models
from django.utils.translation import gettext_lazy as _

class AccessAttempt(models.Model):

    username = models.CharField(_("Username"), max_length=255, null=True, db_index=True)

    failures_since_start = models.PositiveIntegerField(_("Failed Logins"))

validate_jwt_auth.py

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from .models.access_attempt import AccessAttempt
from rest_framework import status
from rest_framework.exceptions import AuthenticationFailed

@transaction.non_atomic_requests
def obtain_tokens(request, credentials):
    attempt = AccessAttempt.objects.filter(username=credentials['username']).first()
    if attempt is None:
        attempt = AccessAttempt.objects.create(
            username=credentials['username'],
            failures_since_start=0
        )
        attempt.save()
    failures = attempt.failures_since_start
    print(failures)
    if failures > 5:
        return {'message': "Failed too many times"}, status.HTTP_403_FORBIDDEN
    try:
        with transaction.atomic():
            payload = TokenObtainPairSerializer(context={'request':request}).validate(credentials)
            attempt.failures_since_start=0
            attempt.save()
            return payload, status.HTTP_200_OK
    except AuthenticationFailed:
        attempt.failures_since_start += 1
        attempt.save()
        print(attempt.failures_since_start)
        return {'message': "Unauthorized"}, status.HTTP_401_UNAUTHORIZED

views.py

def generate_auth(request):
    b = json.loads(request.body)
    if b['username'] is None or b['password'] is None:
        return JsonResponse({'message': "Bad Request"}, status=status.HTTP_400_BAD_REQUEST)
    payload, status = obtain_tokens(request, b)
    return JsonResponse(payload, status=status)
Вернуться на верх