【问题标题】:Proper way to have a nested writable serialization django drf具有嵌套可写序列化 django drf 的正确方法
【发布时间】:2018-10-21 07:23:49
【问题描述】:

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

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 create 方法中,我们有经过验证的项目数据。

我正在使用 django 1.11 和 DRF 3.8.2;

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

    • 简单的解决方案,我没想到会这样。虽然计费实例必须添加到每个项目中所以我不使用many=True并直接调用它。
    猜你喜欢
    • 1970-01-01
    • 2019-11-16
    • 2021-05-23
    • 2016-05-29
    • 1970-01-01
    • 2018-02-12
    • 2021-08-14
    • 2020-08-31
    • 1970-01-01
    相关资源
    最近更新 更多