to_representation принимает два разных типа значений - PullRequest
2 голосов
/ 28 января 2020

Я не понимаю to_reprsentation(self, value) хорошо, у меня есть такой случай

  • , когда я использую postman, статус возвращает "ORDERED, ...", когда я разместить и создать заказ, и value in to_reprsentation имеет тип int

  • , когда я открываю localhost:8000/orders/, я получаю Order объект не может быть преобразован в int, value имеет тип Order на этот раз.

Я искал каждую найденную статью, я не понимал оба метода to_representation & to_internal_value

models.py

class Product(models.Model):
    title = models.CharField(max_length=120)
    price = models.FloatField(max_length=20)

    def __str__(self):
        return f"{self.title} - {self.price}"

    class Meta:
        ordering = ['price']

    @property
    def images(self):
        for image in Image.objects.filter(product=self):
            yield image.src.url

и

class STATUS:
    UNORDERED = 0
    ORDERED = 1
    BEING_PROCESSED = 2
    BEING_DELIVERED = 3
    DELIVERED = 4
    RECEIVED = 5
    REFUND_REQUESTED = 6

и

class Order(models.Model):
    ORDER_STATUS = (
        (STATUS.UNORDERED, 'Unordered'),
        (STATUS.ORDERED, 'Ordered'),
        (STATUS.BEING_PROCESSED, 'Being processed'),
        (STATUS.BEING_PROCESSED, 'Being Delivered'),
        (STATUS.DELIVERED, 'Delivered'),
        (STATUS.RECEIVED, 'Received'),
        (STATUS.REFUND_REQUESTED, 'Refund requested')
    )

    products = models.ManyToManyField(Product)  #
    status = models.IntegerField(choices=ORDER_STATUS, default=STATUS.UNORDERED)

    class Meta:
        ordering = ['pk']

serializers.py

class ProductSerializer(serializers.ModelSerializer):
    images = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = ['id', 'title', 'price', 'images']

    def get_images(self, obj):
        request = self.context.get('request', None)
        for url in obj.images:
            yield request.build_absolute_uri(url)


class StatusField(serializers.RelatedField):
    def to_internal_value(self, value):
        try:
            if int(value) > STATUS.ORDERED:
                raise APIException("Can't update an ordered order.")
        except ValueError:
            raise APIException('Unknown order status code')
        except TypeError:
            raise APIException('Order status must be an integer.')
        return value

    def to_representation(self, value):
        if isinstance(value, Order):
            return value.status if value.status <= STATUS.ORDERED else APIException('Hi')
        # if int(value) == 0:
        #     return "Unordered"
        # elif int(value) == 1:
        #     return "Ordered"
        # elif int(value) == 2:
        #     return "Being processed"
        # elif int(value) == 3:
        #     return "Being Delivered"
        # elif int(value) == 4:
        #     return "Delivered"
        # elif int(value) == 5:
        #     return "Received"
        # elif int(value) == 6:
        #     return "Refund requested"
        # raise serializers.ValidationError('Invalid order status code')


class OrderSerializer(serializers.ModelSerializer):
    products = ProductSerializer(many=True)
    status = StatusField(queryset=Order.objects.all())

    class Meta:
        model = Order
        fields = ['id', 'status', 'products']
        depth = 2

    def create(self, validated_data):  # needs auth
        products_list = validated_data.pop('products')
        order = Order.objects.create(**validated_data)
        for product_data in products_list:
            product = Product.objects.create(**product_data)
            order.products.add(product)
        order.save()
        return order

    def update(self, instance, validated_data):
        products_data = validated_data.pop('products')

        if instance.status >= STATUS.ORDERED:
            raise APIException("Can't update an ordered order")

        instance.status = validated_data.get('status', instance.status)

Если я использую ifInInstance, он будет работать, но я хочу знать, почему иногда он возвращает Order, а в других случаях он возвращает int

документы сказали The value argument will typically be a model instance., и это не произошло в моем case.

Чего мне не хватает?

Заранее спасибо.

1 Ответ

1 голос
/ 29 января 2020

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

Нет необходимости наследовать отдельное поле StatusField для проверки состояния. Вместо этого вы можете использовать функцию validate_<fieldname>. Проверка выполняется при сохранении.

class OrderSerializer(serializers.ModelSerializer):
    def validate_status(self, value):
        try:
            if int(value) > STATUS.ORDERED:
                raise APIException("Can't update an ordered order.")
        except ValueError:
            raise APIException('Unknown order status code')
        except TypeError:
            raise APIException('Order status must be an integer.')
        return value

документы: https://www.django-rest-framework.org/api-guide/serializers/#field -уровневая проверка

Plus, из django 3.0 можно использовать models.IntegerChoices , Вы можете рассмотреть возможность использования этого, если вы используете django 3.0. документы: https://docs.djangoproject.com/en/3.0/ref/models/fields/#enumeration -типы

...