Как обрабатывать транзакции в django Остальные рамки? - PullRequest
0 голосов
/ 02 марта 2020

Я пытаюсь создать простой пост API, используя django rest framework. Данные запроса

{
    "name":"Sweetd Cakeq",
    "protein":"oh1.0",
    "carb":1.0,
    "fat":1.0
}

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

Код, написанный в представлении, как-то работает, но я не уверен, что это правильный подход. может кто-нибудь проверить, правильно ли я это делаю или нет?

Models.py

class Product(models.Model):
    name = models.TextField()

    def __str__(self):
        return self.name


class Ingredient(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="ingredients")
    protein = models.FloatField()
    carb = models.FloatField()
    fat = models.FloatField()

    def __str__(self):
        return self.product.name

Views.py

class GlobalApiResponse():

    def error_response(self, response, status):
        print(response)
        return Response({"error": response, "status": status})

    def success_response(self, data, status):
        return Response({"message": "posted successfully", "data": data, "status": status})


class ProductView(APIView, GlobalApiResponse):
    def post(self, request):
        print(request.data)
        serializer = ProductSerializer(data=request.data)
        if serializer.is_valid():
            with transaction.atomic():
                product = serializer.save()
                request.data['product'] = product.pk
                ing_ser = IngridientSerializer(data=request.data)
                if ing_ser.is_valid():
                    ing_ser.save()
                    return self.success_response(data=serializer.data, status=status.HTTP_201_CREATED)
                else:
                    transaction.set_rollback(True)
                    return self.error_response(response=ing_ser.errors, status=status.HTTP_400_BAD_REQUEST)
        else:
            return self.error_response(response=serializer.errors, status=status.HTTP_400_BAD_REQUEST)

1 Ответ

0 голосов
/ 02 марта 2020

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

class ProductView(APIView, GlobalApiResponse):
    def post(self, request, **kwargs):
        print(request.data)
        serializer = ProductSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        ing_ser = IngridientSerializer(data=request.data)
        ing_ser.is_valid(raise_exception=True)
        try:
            with transaction.atomic():
                product = serializer.save()
                ing_ser.save(product=product)
                return self.success_response(data=serializer.data, status=status.HTTP_201_CREATED)
        except IntegrityError:
            handle_exception()

Django транзакций atomi c:

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

Обработка исключения, IntegrityError

Обратите внимание, что любые операции, предпринятые в atomi c блок будет уже откатан безопасно при вызове handle_exception (), поэтому обработчик исключений также может работать с базой данных при необходимости.

...