【问题标题】:to_representation takes two different value typesto_representation 采用两种不同的值类型
【发布时间】:2020-05-14 04:21:03
【问题描述】:

看不懂to_reprsentation(self, value)好吧,我有这样的案例

  • 当我使用postman 时,当我发布并创建订单并且to_reprsentation 中的valueint 类型时,状态返回“ORDERED, ...”

  • 当我打开localhost:8000/orders/时,我得到Order对象不能转换成intvalue这次是Order类型。

我搜索了我找到的每一篇文章,我不理解to_representationto_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)

如果我使用 if isInstance,它会起作用,但我确实想知道为什么有时它返回 Order 而其他时候它返回 int

文档说 The value argument will typically be a model instance. 而这在我的案例中没有发生。

我错过了什么?

提前致谢。

【问题讨论】:

    标签: django api django-rest-framework model


    【解决方案1】:

    序列化程序文档中描述的字段用于自定义关系字段。这就是文档通常说正在输入模型实例的原因。 status 字段适用于 serializers.IntegerField,而不适用于 serializers.RelationField

    不需要继承单独的 StatusField 来进行状态验证。相反,您可以使用validate_&lt;fieldname&gt; 函数。验证在保存时完成。

    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-level-validation

    另外,从 django 3.0 开始,您可以使用models.IntegerChoices。如果您使用的是 django 3.0,则可以考虑使用它。文档:https://docs.djangoproject.com/en/3.0/ref/models/fields/#enumeration-types

    【讨论】:

    • 您好,感谢您提出另一种解决此问题的方法?但是,我有点担心为什么这不起作用而不是另一种工作方式,在此先感谢。
    • @AhmedI.Elsayed status 在模型中定义为IntegerField,但在序列化程序中定义为RelatedField 很奇怪。一旦你设置了模型和序列化器类型,你就可以让它们以某种方式工作,但是将验证逻辑放入 to_internal_value 是被滥用的。无论如何,您只需要 to_internal_value 而不需要 to_representation。这是因为从外部API保存到数据库时使用to_internal_value,而从数据库转换到外部API时使用to_representation。
    • 昨天很忙没时间测试,今天就去测试告诉你结果。
    • 是的,我认为这很有帮助,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多