Django Rest Framework Правильно ли я делаю?

Я сам изучал DRF и меня беспокоит один вопрос, к сожалению мне не кому его задать и этот вопрос беспокоит меня постоянно. Является ли хорошим подходом написание логики приложения в представлениях (как в приложенном коде)? При отправке запроса на сервер с намерением, например, принять заказ, мне приходится обновлять значения из других моделей, кроме заказа, или проводить валидацию статусов, изменять данные на их основе. В первых учебниках, из которых я узнал, среди прочих, JustDjango вся логика находится в представлении. Однако, после написания некоторого кода и просмотра других руководств, я чувствую, что это не правильный подход. Разве сохранение и обновление моделей не должно осуществляться через сериализатор? Если да, то через один большой сериализатор или несколько маленьких сериализаторов.

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

class UpdateOrderSerializer(serializers.ModelSerializer):
    pzitem_id = serializers.CharField()
    ordered_quantity = serializers.IntegerField()
    user = serializers.PrimaryKeyRelatedField(User.objects.all())
    item = serializers.PrimaryKeyRelatedField(OrderItem.objects.all())

    class Meta:
        model = Order

    def validate(self, attrs):
        attrs = super().validate(attrs)
        if attrs["ordered_quantity"] < 0:
            raise serializers.ValidationError(dict(ordered_quantity="Próbujesz zamówić ujemną wartość"))

    def update(self, instance, validated_data):
        instance.status = "WTZ"
        # do some other things
        instance.save()
        return instance

class ZK_AddUpdateItemWithInstaReservation(ModelViewSet):
    permission_classes = (IsAuthenticated,)
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    @action(detail=True)
    def update_order(self, request, pk):
        serializer = self.get_serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(status=HTTP_200_OK, data={})

Если у вас много операций, которые связаны между собой. Вы можете создать конвейер. Например, так;

class YourPipeline:
    def __init__(self, past_some_data):
        self.past_some_data = past_some_data
        
    def update_order_status(self):
        # update your order
        
    def create_order_item(self):
        # do something else    
    
    def some_function(self):
        # another operation
    
    def run(self):
        self.update_order_status()
        self.create_order_item()
        self.some_function()
        return instance


class UpdateOrderSerializer(serializers.ModelSerializer):
    pzitem_id = serializers.CharField()
    ordered_quantity = serializers.IntegerField()
    user = serializers.PrimaryKeyRelatedField(User.objects.all())
    item = serializers.PrimaryKeyRelatedField(OrderItem.objects.all())

    class Meta:
        model = Order

    def validate(self, attrs):
        attrs = super().validate(attrs)
        if attrs["ordered_quantity"] < 0:
            raise serializers.ValidationError(dict(ordered_quantity="Próbujesz zamówić ujemną wartość"))

    def update(self, instance, validated_data):
        pipeline = YourPipeline(past_some_data=past_some_data)
        return pipeline.run()
        

class ZK_AddUpdateItemWithInstaReservation(ModelViewSet):
    permission_classes = (IsAuthenticated,)
    serializer_class = OrderSerializer
    queryset = Order.objects.all()

    @action(detail=True)
    def update_order(self, request, pk):
        serializer = self.get_serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(status=HTTP_200_OK)

На мой взгляд, в вашем случае в коде есть несколько ошибок:

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

    .
  2. В случае ошибок вы не должны возвращать код состояния 200, только одну из 4XX ошибок

  3. Если вы хотите уменьшить или увеличить поле модели:

item.quantity_not_ordered -= int(ordered_quantity)

вам следует использовать https://docs.djangoproject.com/en/4.0/ref/models/expressions/#avoiding-race-conditions-using-f

  1. Вы не должны использовать
try:
  foo()
except:
  pass

Отличная практика заключается в явном перехвате всех исключений, которые могут возникнуть

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