嵌套嵌套可写序列化的正确方法

时间:2018-10-21 07:23:50

标签: django django-rest-framework django-serializer

假设我有两个带有两个序列化器的模型,一个具有另一个作为嵌套序列化器的模型,如下所示:

class Item(models.Model):
  ...
  discounts = ManyToManyField(Discount)
  gift_discounts = ManyToManyField(GiftDiscount)
  ...

class Billing(models.Model):
  ...
  items = ManyToManyField(Item)
  ...

# serializers
class ItemSerializer(serializers.ModelSerializer):
  ...
  def create(self, validated_data):
    discounts = validated_data.pop('discounts')
    gift_discounts = validated_data.pop('gift_discounts')
    item = super(ItemSerializer, self).create(**validated_data)
    for discount in discounts:
      item.discounts.add(discount)
    for gift_discount in gift_discounts:
      item.gift_discounts.add(gift_discount)

class BillingSerializer(serializers.ModelSerializer):
  items = ItemSerializer(queryset=Item.objects.all(), many=True)
  ...
  def create(self, validated_data):
    items = validated_data.pop('items')
    billing = super(BillingSerializer, self).create(**validated_data)

    for item in items:
      discounts = item.pop('discounts')
      gift_discounts = item.pop('gift_discounts')

      sell_item = Item.objects.create(**item)

      for discount in discounts:
        sell_item.discounts.add(discount)

      for gift_discount in gift_discounts:
        sell_item.gift_discounts.add(gift_discount)

如您所见,在这种情况下,我必须编写两次相同的代码来在物料序列化程序中创建一个物料,在帐单序列化程序中创建另一个物料,这违背了DRY规则,并且可能会变得更加复杂且容易出错进步。我正在寻找一种只编写一次代码并在两个地方都使用的方法。

也许在ItemSerializer中有一个类方法是一种解决方案,但不是完整的解决方案,因为您可能不需要很多ItemSerializer方法和成员。我认为最好的解决方案是创建一个序列化程序,不包含原始数据,而是包含经过验证的数据,因为在Billing创建方法中,我们具有项目的经过验证的数据。

我正在使用django 1.11和DRF 3.8.2;

1 个答案:

答案 0 :(得分:1)

您也可以使用Item序列化程序在BillingSerializer中创建项目,如下所示:

class BillingSerializer(serializers.ModelSerializer):
  items = ItemSerializer(queryset=Item.objects.all(), many=True)
  ...
  def create(self, validated_data):
    items_validated_data = validated_data.pop('items')
    instance = super(BillingSerializer, self).create(validated_data)
    items = ItemSerializer(many=True).create(items_validated_data)

    instance.items.set(items)
    return billing