Избегайте проверки внешнего ключа в сериализаторе django rest framework - PullRequest
0 голосов
/ 13 апреля 2019

Я пишу API для следующих моделей:

class TemplateProjectGroup(models.Model):
    pass


class TemplateProject(models.Model):
    name = models.CharField(max_length=255, unique=True)
    description = models.CharField(max_length=1024, blank=True)
    group = models.ForeignKey(TemplateProjectGroup, on_delete=models.CASCADE)
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    avatar_url = models.URLField(max_length=1024, blank=True)

Логика следующая: пользователь может создать экземпляр TemplateProject с несуществующим полем group. Таким образом, если группа не существует, она должна быть создана с определенным идентификатором. Итак, у меня есть этот сериализатор:

class TemplateProjectSerializer(serializers.ModelSerializer):

    def create(self, validated_data):
        template_project_group_id = validated_data.pop('group')
        project = validated_data.pop('project')
        group, _ = models.TemplateProjectGroup.objects.get_or_create(id=template_project_group_id)
        template_project = models.TemplateProject.objects.create(**validated_data, group_id=group.id, project_id=project.id)
        return template_project

    def update(self, instance, validated_data):
        template_project_group_id = validated_data.pop('group')
        group, _ = models.TemplateProjectGroup.objects.get_or_create(id=template_project_group_id)
        instance.save()
        instance.update(**validated_data, group=group)
        return instance

    class Meta:
        model = models.TemplateProject
        fields = ('name', 'description', 'group', 'project', 'avatar_url')

и вид:

class TemplateProjectsView(generics.ListCreateAPIView):
    pagination_class = None

    serializer_class = serializers.TemplateProjectSerializer

    def get_queryset(self):
        return models.TemplateProject.objects.all() 

Хорошо работает, когда я пытаюсь получить список объектов, но я не могу создать объект с помощью этого API, потому что я получаю следующую ошибку:

Invalid pk "1" - object does not exist.

Таким образом, перед созданием объекта применяется проверка для всех полей, и сериализатор не может сериализовать это целое число в объект, поскольку этот объект, на который ссылается внешний ключ, не существует. Я написал метод validate_group(self, value), но исключение возникает до того, как точка выполнения прибывает в этот метод. Более близким моментом, который я мог бы поставить в отладчике, является метод is_valid(self, raise_exception=False). Я мог бы создавать отсутствующие объекты там, но я думаю, что это было бы плохой практикой, потому что этот метод на самом деле не имеет целью проверку или подготовку данных.

Как правильно создать объект, прежде чем он пройдет все проверки?

1 Ответ

0 голосов
/ 13 апреля 2019

Один из возможных вариантов - явно указать group как целочисленное поле. Таким образом, поле группы не будет проверяться как экземпляр TemplateProjectGroup .

class TemplateProjectSerializer(serializers.ModelSerializer):
    group = serializers.IntegerField(source='group.id')
    ...

С помощью этой настройки вы можете получить идентификатор группы, подобный этому, при создании или обновлении метода сериализатора:

template_project_group_id = validated_data.pop('group').get('id')

Другой вариант: вы можете получить или создать экземпляр группы в представлении, получив идентификатор группы из запроса, а затем всегда передавать существующий идентификатор группы в сериализатор и ожидать существующий идентификатор группы в сериализаторе. Это будет означать перемещение некоторой логики проверки в представление (вам нужно будет хотя бы проверить, предоставлено ли целое число для поля группы), но вам не нужно настраивать ваш сериализатор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...