【问题标题】:Serializing nested objects in DRF序列化 DRF 中的嵌套对象
【发布时间】:2020-05-04 15:28:17
【问题描述】:

我的网站上有一个测试对象,我正试图正确地进入数据库。 它是一个带有嵌套产品数据的订单对象。 下面是前端发布的 JSON 示例:

{
    "phone": "123456789",
    "first_name": "name",
    "delivery_date": "2020-01-06",
    "delivery_time": 2,
    "address": "address",
    "comment": "comment",
    "payment": 0,
    "order_items": [
      {
        "quantity": 2,
        "pizza": 1
      },
      {
        "quantity": 3,
        "pizza": 2
      }
    ]
}

这是我的serializers.py

class OrderItemSerializer(serializers.ModelSerializer):
    quantity = serializers.IntegerField()
    pizza = serializers.SerializerMethodField()
    print(pizza, quantity)

    def get_pizza(self, obj):
        print(obj.pizza.id)
        return obj.pizza.id

    class Meta:
        model = OrderItem
        fields = ('quantity',
                  'pizza',)


class OrderSerializer(serializers.ModelSerializer):
    order_items = serializers.SerializerMethodField()

    """
    Calculate order_items field 
    """
    def get_order_items(self, obj):
        items = obj.orderitem_set.all()
        print(obj)
        print(items)
        return OrderItemSerializer(items, many=True).data

    class Meta:
        model = Order
        fields = ('phone',
                  'first_name',
                  'delivery_date',
                  'delivery_time',
                  'address',
                  'comment',
                  'payment',
                  'order_items',)

因此,order_items 始终为空: "order_items": []

我正在使用 Swagger 来测试和记录 API。我可以直接从那里发布订单而没有错误,但即使我手动添加订单项目,它们仍然不会出现在服务器响应正文中。这一定意味着我没有正确处理嵌套对象。

发布

{
    "phone": "123456",
    "first_name": "string",
    "delivery_date": "2000-10-21",
    "delivery_time": 2,
    "address": "string",
    "comment": "string",
    "payment": 0,
    "order_items": [
        {"pizza": 2,"quantity": 3},
        {"pizza": 1,"quantity": 4}]
}

201,响应正文:

{
  "phone": "123456",
  "first_name": "string",
  "delivery_date": "2000-10-21",
  "delivery_time": 2,
  "address": "string",
  "comment": "string",
  "payment": 0,
  "order_items": []
}

我还在上面的代码中设置了一些print 行,看起来OrderItemSerializer 根本没有被使用。 get_order_items 打印订单 id 和一个空数组,而 get_pizza 在网站下订单时不打印任何内容。

【问题讨论】:

    标签: json django api django-rest-framework


    【解决方案1】:

    最终我想出了这个。 我不得不将order_items 变量添加到Order 对象,它没有以任何方式被使用,只会浪费数据库中的空间。虽然不是很大的浪费,但我觉得无论如何都不是写代码的好方法。

    如果有人可以在 cmets 或其他答案中提出更好的版本,我也会尝试一下。

    from rest_framework import serializers
    from .models import Order, OrderItem
    import copy
    
    
    class OrderItemSerializer(serializers.ModelSerializer):
        class Meta:
            model = OrderItem
            fields = ('quantity',
                      'pizza',)
    
    
    class OrderSerializer(serializers.ModelSerializer):
        order_items = OrderItemSerializer(many=True)
    
        class Meta:
            model = Order
            fields = ('phone',
                      'first_name',
                      'delivery_date',
                      'delivery_time',
                      'address',
                      'comment',
                      'payment',
                      'order_items')
    
        def create(self, validated_data, **kwargs):
            for_items = copy.deepcopy(validated_data)
    
            # create order object
            del validated_data['order_items']
            print('VALID', validated_data)
            order = Order.objects.create(**validated_data)
    
            # create order items
            for item in for_items.pop('order_items'):
                order_item = dict(item.items())
                print('ITEM', order_item)
                OrderItem.objects.create(order=order, **order_item)
    
            return order
    

    【讨论】:

      【解决方案2】:

      您需要重写序列化程序的create() 方法以生成writable nested serializers

      试试这样的:

      class OrderSerializer(serializers.ModelSerializer):
          order_items = serializers.SerializerMethodField()
      
          """
          Calculate order_items field 
          """
          def get_order_items(self, obj):
              items = obj.orderitem_set.all()
              print(obj)
              print(items)
              return OrderItemSerializer(items, many=True).data
      
          class Meta:
              model = Order
              fields = ('phone',
                        'first_name',
                        'delivery_date',
                        'delivery_time',
                        'address',
                        'comment',
                        'payment',
                        'order_items',)
      
          def create(self, validated_data):
              items_data = validated_data.pop('order_items')
              order = Order.objects.create(**validated_data)
              for item_data in items_data:
                  OrderItem.objects.create(order=order, **item_data)
              return order
      

      您也可以只使用OrderItemSerializer 作为字段而不使用SerializerMethodField。您可以使用source 参数指定字段source

      order_items = serializers.OrderItemSerializer(many=True, source="orderitem_set")
      

      【讨论】:

      • 使用了相同的文档。据我了解,create 使用数组,我的数组是空的。所以我假设问题出在OrderItemSerializerprint(obj.pizza.id) 没有打印任何内容,这意味着首先没有数据。
      • @GlebIvanov print(obj.pizza.id) 未打印,因为相关项目在 POST 请求期间未保存。您是否尝试覆盖 create 方法?
      • 是的。之前尝试过,如文档中所示。明白了:'Order' object has no attribute 'order_items'. OrderItems 模型对 Order 有外键,所以我不需要将此字段添加到 Order,只需创建其中包含订单 ID 的对象。
      • @GlebIvanov 很难说没有实际的回溯,但我想'Order' object has no attribute 'order_items'create 方法无关。并且很可能与序列化程序的字段有关。订单模型没有order_items 属性,据我所知,它是orderitem_set 根据您的代码。所以在序列化器的字段上使用source="orderitem_set" 参数应该可以修复它。尝试使用我的答案中的代码,希望这能奏效。
      • 好的,所以我是否使用source 字段似乎并不重要。我得到的回复是{'phone': 'string', 'first_name': 'string', 'delivery_date': datetime.date(2000, 10, 21), 'delivery_time': 2, 'address': 'string', 'comment': 'string', 'payment': 0, 'o rder_items': [OrderedDict([('quantity', 3), ('pizza', <Pizza: Chicken>)])]}。问题似乎出在 OrderedDict 对象中。有没有办法解压它,或者我应该改变它在前端的生成方式?
      猜你喜欢
      • 2020-10-03
      • 2020-12-20
      • 1970-01-01
      • 1970-01-01
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      • 2016-08-14
      • 2022-06-14
      相关资源
      最近更新 更多