嵌套序列化程序中的Django发布信息

时间:2019-02-13 07:54:22

标签: django django-rest-framework

我有3个模型:Workflow,WorkflowLevels,WorkflowLevelPermissions:

models.py:

class Workflow(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4,
                          editable=False)
    name = models.CharField(max_length=32, default=None, null=True)
    description = models.CharField(max_length=100, default=None,
                                   null=True)
    tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE,
                               default=None, null=False)

    class Meta:
        unique_together = ('name', 'tenant')


class WorkflowLevel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4,
                          editable=False)
    workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE,
                                 related_name='levels', default=None,
                                 null=False)
    level = models.IntegerField(default=None, null=False)
    operation = models.CharField(max_length=32, default=None,
                                 null=False)

    class Meta:
        unique_together = ('workflow', 'level')


class WorkflowPermission(models.Model):
    short_name = models.CharField(max_length=32, primary_key=True,
                                  default=None, null=False)


class WorkflowLevelPermission(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4,
                          editable=False)
    level = models.ForeignKey(WorkflowLevel, on_delete=models.CASCADE,
                              default=None, null=False,
                              related_name='workflow_permissions')
    permission = models.ForeignKey(WorkflowPermission,
                                   on_delete=models.CASCADE,
                                   default=None, null=False)

    class Meta:
        unique_together = ('level', 'permission')

    def short_name(self):
        return self.permission.short_name

我使用嵌套的序列化器以这种格式显示工作流数据

.json:

[
  {
    "name": "test",
    "description": "Easy",
    "levels": [
        {
            "level": 1,
            "operation": "AND",
            "workflow_permissions": [
                {
                    "short_name": "admin_approval"
                },
                {
                    "short_name": "coordinator_approval"
                }
            ]
        },
        {
            "level": 2,
            "operation": "AND",
            "workflow_permissions": []
        }
      ]
   }
]

序列化器:

class WorkflowPermissionSerializer(serializers.ModelSerializer):

    class Meta:
        model = WorkflowPermission
        fields = '__all__'


class WorkflowLevelPermissionSerializer(serializers.ModelSerializer):
    short_name = serializers.SerializerMethodField('short_name')

    class Meta:
        model = WorkflowLevelPermission
        fields = ['short_name']

    def short_name(self):
        return self.permission.short_name


class WorkflowLevelSerializer(serializers.ModelSerializer):
    workflow_permissions = WorkflowLevelPermissionSerializer(many=True)

    class Meta:
        model = WorkflowLevel
        fields = ['level', 'operation', 'workflow_permissions']


class WorkflowSerializer(serializers.ModelSerializer):
    levels = WorkflowLevelSerializer(many=True)

    class Meta:
         model = Workflow
        fields = ('name', 'description', 'levels')

我希望能够在Workflow API视图中以相同格式发布数据。现在它显示错误: .create()方法默认情况下不支持可写的嵌套字段。 为串行器.create()编写一个显式的exzaacademy.els.tenantmgmt.serializers.WorkflowSerializer方法,或在嵌套的串行器字段上设置read_only=True。 如何编写正确的create()方法?

我将create方法覆盖为:

class WorkflowSerializer(serializers.ModelSerializer):
  levels = WorkflowLevelSerializer(many=True)

  class Meta:
    model = Workflow
    fields = ('name', 'description', 'levels', 'tenant')

    def create(self, validated_data):
    levels = validated_data.pop('levels')
    workflow = Workflow.objects.create(**validated_data)

    for level in levels:
        permissions = level.pop('workflow_permissions')
        level=WorkflowLevel.objects.create(
            workflow=workflow,
            level=level['level'],
            operation=level['operation']
        )

        for permission in permissions:
            WorkflowLevelPermission.objects.create(
                level=level,
                permission=permission
            )

    return workflow

出现错误:WorkFLowLevelPermission.level必须是一个关卡实例

3 个答案:

答案 0 :(得分:2)

您需要做的是在串行器create中覆盖WorkflowSerializer函数,如此处所述:https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers。请记住,对于POST create以及PUTPATCH覆盖update。在这里,您必须执行手动创建/更新模型的逻辑。您始终可以访问来自validated_data的接收数据和来自self.initial_data的原始数据。请按照上述可写嵌套序列化程序指南进行操作。

在这里,我看到您在嵌套序列化程序中还有另一个嵌套序列化程序。因此,实现起来可能会很复杂。

在这种情况下,以下指南可能会非常有用:https://medium.com/profil-software-blog/10-things-you-need-to-know-to-effectively-use-django-rest-framework-7db7728910e0

请参见部分9。在嵌套的序列化程序中处理多个创建/更新/删除

答案 1 :(得分:1)

class WorkflowSerializer(serializers.ModelSerializer):
  levels = WorkflowLevelSerializer(many=True)

  class Meta:
    model = Workflow
    fields = ('name', 'description', 'levels', 'tenant')

    def create(self, validated_data):
    levels = validated_data.pop('levels')
    workflow = Workflow.objects.create(**validated_data)

    for level in levels:
        permissions = level.pop('workflow_permissions')
        level_var = WorkflowLevel.objects.create( # Change Here
            workflow=workflow,
            level=level['level'],
            operation=level['operation']
        )

        for permission in permissions:
            WorkflowLevelPermission.objects.create(
                level=level_var, # Change Here
                permission=permission
            )

    return workflow

答案 2 :(得分:0)

这对我有用:

class WorkflowSerializer(serializers.ModelSerializer):
 levels = WorkflowLevelSerializer(many=True)

 class Meta:
    model = Workflow
    fields = ('name', 'description', 'levels')

 def create(self, validated_data):
    levels = validated_data.pop('levels')
    workflow=Workflow.objects
   .create(**validated_data,tenant=self.context['request'].user.tenant)

    for index,level in enumerate(levels):
        permissions = level.pop('workflow_permissions')
        level_var = WorkflowLevel.objects.create(
            workflow=workflow,
            level=level['level'],
            operation=level['operation']
        )
        print("Initial data",self.initial_data)
        for permission in self.initial_data['levels'][index]['workflow_permissions']:
            permission_obj = WorkflowPermission.objects
           .filter(short_name=permission['short_name']).first()
            WorkflowLevelPermission.objects.create(
                id=uuid.uuid4().hex,
                level=level_var,
                permission=permission_obj
            )

    return workflow