Пост Джанго во вложенном сериализаторе - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть 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')

Я хочу иметь возможность POST-данных в том же формате в представлении Workflow API. Теперь он показывает ошибку: *Метод 1014 * не поддерживает записи вложенных полей по умолчанию.Напишите явный метод .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 голосов
/ 13 февраля 2019
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
0 голосов
/ 13 февраля 2019

Это сработало для меня:

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
0 голосов
/ 13 февраля 2019

вам нужно переопределить функцию create в сериализаторе WorkflowSerializer, как указано здесь: https://www.django -rest-framework.org / api-guide / relations / # writable-nested-serializers .имейте в виду, что для POST create и для PUT или PATCH переопределите 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.Обработка нескольких созданий / обновлений / удалений во вложенных сериализаторах

...