Django Rest Framework - 创建作为嵌套对象的列表属性传递的对象

时间:2014-04-18 11:19:19

标签: django django-rest-framework

Xzibit开玩笑说,这是我的模特:

from django.db import models

class ProjectProfitAndLoss(models.Model):
    pass

class Component(models.Model):
    profit_and_loss = models.ForeignKey(ProjectProfitAndLoss, related_name='components')
    name = models.CharField(max_length=250)

class ComponentProductionVolume(models.Model):
    component = models.ForeignKey(Component, related_name='volumes')
    offset = models.IntegerField()
    volume = models.DecimalField(max_digits=16, decimal_places=4)

串行器:

from rest_framework import serializers

class ComponentProductionVolumeSerializer(serializers.ModelSerializer):
    class Meta:
        model = ComponentProductionVolume


class ComponentSerializer(serializers.ModelSerializer):
    volumes = ComponentProductionVolumeSerializer(many=True, allow_add_remove=True)

    class Meta:
        model = Component


class ProjectProfitAndLossSerializer(serializers.ModelSerializer):
    components = ComponentSerializer(many=True, allow_add_remove=True)

    class Meta:
        model = ProjectProfitAndLoss

我尝试做的是将要创建的组件与其ComponentProductionVolumes一起列为列表 - 也作为列表。所以我的json看起来像这样:

[
  {
    "name": "component 1",
    "profit_and_loss": 3,
    "volumes": [
      {
        "offset": 0,
        "volume": 2
      },
      {
        "offset": 1,
        "volume": 3
      },
      {
        "offset": 2,
        "volume": 2
      },
    ]
  },
  {
    "name": "component 2"
    "profit_and_loss": 3,
    "volumes": [
      {
        "offset": 0,
        "volume": 4
      },
      {
        "offset": 1,
        "volume": 2
      },
      {
        "offset": 2,
        "volume": 5
      },
    ]
  }
]

不幸的是,我收到的是验证错误:

components: [{volumes:[{component:[This field is required.]},{volumes:[{component:[This field is required.]} ... /* error repeated for each volume sent */ ]}] 

如果我理解正确,这个错误告诉我在我发送的每个卷中包含组件ID。但由于我希望DRF创建组件及其卷,这是不可能的,因为组件尚不存在。

什么是使DRF创建组件的最佳方法,然后是ComponentProductionVolumes?

2 个答案:

答案 0 :(得分:3)

当前DRF(版本2.3.13)没有内置功能来创建嵌套关系。但是,通过覆盖create中的ListCreateView来完成此操作是非常简单的:

class ComponentList(generics.ListCreateAPIView):
    model = Component
    serializer_class = ComponentSerializer

    def create(self, request, *args, **kwargs):
        data = request.DATA

            # note transaction.atomic was introduced in Django 1.6
            with transaction.atomic():
                component = Component(
                    profit_and_loss=data['component_comments'],
                    name=data['name']
                )
                component.clean()
                component.save()

                for volume in data['volumes']:
                    ComponentProductionVolume.objects.create(
                        component=component,
                        offset=volume['offset'],
                        volume=volume['volume']
                    )

        serializer = ComponentSerializer(component)
        headers = self.get_success_headers(serializer.data)

        return Response(serializer.data, status=status.HTTP_201_CREATED,
                        headers=headers)

注意

上面的代码使用了Django 1.6中引入的transaction.atomic。它在这种情况下派上用场,因为如果出现问题,它会回滚更改。有关更多信息,请参阅有关事务的Django文档:

https://docs.djangoproject.com/en/dev/topics/db/transactions/

此外,此示例创建一个Component实例,但创建多个实例可以通过修改客户端一次发送一个Component POST请求或修改上述代码来完成。

希望这有帮助!

答案 1 :(得分:2)

更新问题背景的答案

目前在DRF 3.1中,支持此功能,您可以查看完整文档here