Django 双嵌套序列化器

Django double nested serializer

我正在编写一个 api 的应用程序,其中 Order 是一个提供有关客户想要购买的信息的实体,一个 Order 可以包含具有不同数量和不同价格的不同产品。在订单中包含此信息的实体称为订单详细信息。

我在使用双嵌套序列化程序时遇到了一些问题。

在 post 请求后:

{
    "external_id": "PR-123-321-123",
    "details": [{
        "product": {"id": 4},
        "amount": 10,
        "price": "12.00"
    }, ... ]
}

我想得到这样的回应:

{
    "id": 1,
    "status": "new",
    "created_at": "2021-01-01T00:00:00",
    "external_id": "PR-123-321-123",
    "details": [{
        "id": 1,
        "product": {"id": 4, "name": "Dropbox"},
        "amount": 10,
        "price": "12.00"
    }, ... ]
}

但现在我有一些错误:“无法分配“OrderedDict()”:“OrderDetail.product”必须是“Product”实例。“

怎么了?

型号:

from django.db import models


class Order(models.Model):
    STATUS_CHOICES = (
        ('new', 'new'),
        ('accepted', 'accepted'),
        ('failed', 'failed')
    )
    status = models.CharField(max_length=12, choices=STATUS_CHOICES, default='new')
    created_at = models.DateTimeField(auto_now_add=True)
    external_id = models.CharField(max_length=128, unique=True)


class Product(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name


class OrderDetail(models.Model):
    order = models.ForeignKey(Order, related_name='details', on_delete=models.CASCADE)
    amount = models.IntegerField()
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    price = models.DecimalField(max_digits=8, decimal_places=2)

    def __str__(self):
        return f'{self.order} detail'

序列化程序:

from rest_framework import serializers
from rest_framework.serializers import ModelSerializer

from order.models import Order, Product, OrderDetail


class ProductSerializer(ModelSerializer):
    class Meta:
        model = Product
        fields = '__all__'
        read_only_fields = ('name', )


class OrderDetailSerializer(ModelSerializer):
    product = ProductSerializer()

    class Meta:
        model = OrderDetail
        fields = (
            'id',
            'product',
            'amount',
            'price'
        )


class OrderSerializer(ModelSerializer):
    details = OrderDetailSerializer(many=True)
    status = serializers.CharField(source='get_status_display', read_only=True)

    class Meta:
        model = Order
        fields = (
            'id',
            'status',
            'created_at',
            'external_id',
            'details'
        )

    def create(self, validated_data):
        details_data = validated_data.pop('details')
        order = Order.objects.create(**validated_data)
        for detail_data in details_data:
            OrderDetail.objects.create(**detail_data, order=order)
        return order

修改 OrderSerializer 的创建方法,在创建 OrderDetail 对象之前先获取 Product 实例。

class OrderSerializer(ModelSerializer):
    details = OrderDetailSerializer(many=True)
    status = serializers.CharField(source='get_status_display', read_only=True)

    class Meta:
        model = Order
        fields = (
            'id',
            'status',
            'created_at',
            'external_id',
            'details'
        )

    def create(self, validated_data):
        details_data = validated_data.pop('details')
        order = Order.objects.create(**validated_data)
        for detail_data in details_data:
            try:
                product = Product.objects.get(**detail_data.pop('product'))
                OrderDetail.objects.create(**detail_data, order=order, product=product)
            except (Product.DoesNotExist, Product.MultipleObjectsReturned):
                raise serializers.ValidationError('Your custom error message...')
        return order
class OrderSerializer(serializers.ModelSerializer):
    order = OrderDetailSerializer(many=True, source='order_set', required=False)

    class Meta:
        model = Order
        fields = (
            'id',
            'status',
            'created_at',
            'external_id',
            'details'
        )
 
    def create(self, validated_data):
        if 'order_set' in validated_data:
            order = validated_data.pop('order_set')
        else:
            order = []    
        instance = super().create(validated_data)

        for cd in order:
           instance.order_set.create(**cd)
        return instance

    
       
    def create(self, *args, **kwargs):
        order = Order.objects.create(external_id=self.context.get('request').data.get('external_id'))
        OrderDetail.objects.bulk_create(
            [OrderDetail(**order_detail, order=order, product=Product.objects.get(**order_detail.pop('product')))
             for order_detail in self.context.get('request').data.get('details')]
        )
        return order