Как совместить проверку с select_for_update? - PullRequest
0 голосов
/ 28 сентября 2019

Я занимаюсь разработкой биллинговой / банковской системы.Есть 2 модели счета и транзакции.При создании транзакции я хочу проверить сумму транзакции <остаток на счете.Я использую django-admin и DRF.В обоих случаях пользователь должен видеть сообщения об ошибках валидации.В текущей реализации пользователь видит код ответа 500. Есть ли лучший способ проверки транзакции после блокировки строк? </p>

class Account(models.Model):
    balance = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    datetime = models.DateTimeField(auto_now=True)


class Transaction(models.Model):
    src = models.ForeignKey(Account, on_delete=models.CASCADE, related_name="out_transactions")  
    dst = models.ForeignKey(Account, on_delete=models.CASCADE, related_name="in_transactions")  
    amount = models.DecimalField(max_digits=10, decimal_places=2)  
    datetime = models.DateTimeField(auto_now_add=True)

    def save(self, *args, **kwargs):
        with transaction.atomic():
            Account.objects.select_for_update().filter(pk__in=[self.src.id, self.dst.id])

            if self.src.balance < self.amount:
                raise ValueError('Not enough balance')

            self.src.balance -= self.amount
            self.dst.balance += self.amount
            self.src.save()
            self.dst.save()
            super().save(*args, **kwargs)

1 Ответ

0 голосов
/ 28 сентября 2019

Если вам нужно вернуть ошибку проверки пользователям, то лучше обработать ее на стороне DRF / views.Например, если вы используете видовой набор DRF, то переопределите метод perform_create - оберните создание транскрипции в блок try-кроме, перехватите этот ValueError и верните ответ 400:

    def perform_create(self, serializer):
        try:
            instance = serializer.save()
        except ValueError:
            raise ValidationError(...)

Кстати, это будетздесь безопаснее поднять / перехватить какое-то пользовательское исключение, а не ValueError, чтобы мы не сообщали неверно «Недостаточно баланса» в случае какого-либо другого условия ошибки.

...