【问题标题】:Django Rest Framework - create objects passed as a list attribute of nested objectDjango Rest Framework - 创建作为嵌套对象的列表属性传递的对象
【发布时间】:2015-05-26 11:19:44
【问题描述】:

除了 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 的最佳方法是什么?

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    DRF 当前(2.3.13 版)没有内置功能来创建嵌套关系。但是,通过在 ListCreateView 中覆盖 create 来实现这一点非常简单:

    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 实例,但可以通过修改客户端一次发送一个组件 POST 请求或修改上述代码来创建多个。

    希望这会有所帮助!

    【讨论】:

    • 感谢您的回答。我已经解决了这个问题,但方式略有不同。我覆盖了 ComponentSerializer 上的 restore_object 方法,然后做了几乎相同的事情,但使用 ComponentProductionVolumeSerializer(data=data['volumes'], many=True) 一次反序列化所有卷 - 这给了我每个卷的验证错误个人体积。我一直在寻找你使用的类似 transaction.atomic() 的东西 - 现在肯定会经常使用它。
    • @TomChristie 这个问题在 2.3.14 中修复了吗?
    • @AlexRothberg 查看 2.3.14 发行说明,似乎并非如此。我相信 2.4 版本计划使用可写嵌套功能,但您可以 ask Tom on the google group
    • 在事务中我看到ComponentComponentProductionVolume 是手动创建的,有什么理由不能像在原始实现中那样使用这些模型的序列化器吗?
    【解决方案2】:

    更新问题上下文的答案

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

    【讨论】:

      猜你喜欢
      • 2017-12-29
      • 2017-04-09
      • 1970-01-01
      • 1970-01-01
      • 2021-11-30
      • 2014-07-07
      • 2016-01-22
      • 1970-01-01
      • 2020-07-11
      相关资源
      最近更新 更多