【问题标题】:Django post in nested serializer嵌套序列化程序中的 Django 帖子
【发布时间】:2019-02-13 07:54:22
【问题描述】:

我有 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() 方法默认不支持可写嵌套字段。 为序列化器exzaacademy.els.tenantmgmt.serializers.WorkflowSerializer 编写显式.create() 方法,或在嵌套序列化器字段上设置read_only=True。 如何编写正确的 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 必须是关卡实例

【问题讨论】:

标签: django django-rest-framework


【解决方案1】:

您需要做的是覆盖序列化程序WorkflowSerializer 中的create 函数,如此处所述:https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers。请记住,对于 POST createPUTPATCH 覆盖 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 节。在嵌套序列化程序中处理多个创建/更新/删除

【讨论】:

  • 在这种情况下我可以直接复制 mixin 并用 create 替换 update 吗? (如第二个链接所示)
  • 能否请您重新解决问题?我已经更新了我写的创建方法!
  • 你有多个 levels 并且每个 level 有多个 workflow_permissions 所以在第一个 for 循环 for level in levels: 中,将每个级别视为嵌套对象和 popworkflow_permissions然后保存级别,之后 为每个 workflow_permission 创建具有已创建级别的工作流权限。基本上 将每个级别视为嵌套对象并像第一个 for 循环一样做类似的事情
  • 对于更新编辑中的具体问题,请更改为level = WorkflowLevel.objects.create( workflow=workflow, level=level['level'], operation=level['operation'] )
  • 你能在这里发帖回答吗?
【解决方案2】:
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

【讨论】:

  • 无法分配“OrderedDict()”:“WorkflowLevelPermission.permission”必须是“WorkflowPermission”实例...现在权限 arg 显示相同的错误
  • 我认为是因为权限实际上存储在另一个模型工作流权限中]
  • 然后创建permission = Permission.objects.create(short_name=[put value here]) 然后创建WorkflowLevelPermission
  • 不是那样的......看我的 WorkflowLevelPermissionSerializer 我得到了一个 short_name,它给出了 self.permission.short_name ..这个“权限”是一个 workflowPermission 实例
  • SerializerMethodField 是一个只读字段,因此它验证了数据赋予其值,要么更改SerializerMethodField,要么访问该值表单self.initial_data
【解决方案3】:

这对我有用:

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

【讨论】:

    猜你喜欢
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    • 2019-12-23
    • 2020-03-21
    • 2019-08-02
    • 1970-01-01
    • 2020-12-06
    相关资源
    最近更新 更多