Не удается обработать ошибку DoesNotExist с вложенными ресурсами

#python #django #django-rest-framework

Вопрос:

У меня возникли проблемы с обработкой ошибки DoesNotExist, я использую DRF и DRF-Вложенные маршрутизаторы, и когда я создаю новый объект Like, мне нужна фотография PK, чтобы я мог добавить ее в объект Like.

Я пытаюсь поймать ошибку, которую я получаю, когда фотография с этим ПК не существует. Вот как я создаю подобное в сериализаторе:

 class LikeModelSerializer(serializers.ModelSerializer):
    """ Like model serializer. """

    user = serializers.CharField(default=serializers.CurrentUserDefault())

    class Meta:
        """ Meta class. """

        model = Like
        fields = ('user', 'photo')
        read_only_fields = ('user', 'photo')

    def create(self, validated_data):
        # Get the photo pk from the view context (DRF-nested-routers) and
        # create the new like with the validated_data
        photo_pk = self.context['view'].kwargs["photo_pk"]
        try:
            photo = Photo.objects.get(id=photo_pk)
        except Photo.DoesNotExist:
            return Response(data={'detail': "The photo doesn't exist."}, status=status.HTTP_404_NOT_FOUND)
        validated_data["photo"] = photo
        like, created = Like.objects.get_or_create(**validated_data)
        if created:
            photo.total_likes  = 1
            photo.save()
        return like
 

perform_create представления:

 def perform_create(self, serializer):
    """ Creates a new like.

    The substraction in the total_likes is made in the serializer.
    """
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(data=serializer.data, status=status.HTTP_200_OK)
 

Ответ, который я получаю на это, таков: {'user': 'my username here'}

Я тоже пробовал, except Photo.DoesNotExist но это дает тот же результат.

Комментарии:

1. Можете ли вы поделиться данными запроса и всем сериализатором?

2. Вы написали: photo_pk = self.context['view'].kwargs["photo_pk"] , вы уверены, что контекст сериализатора содержит эти объекты? Пожалуйста, предоставьте полную информацию об ошибке.

3. Я добавил больше кода, полный сериализатор и perform_create. Да, в контексте есть photo_pk, ошибка, которую я получаю Photo.DoesNotExist: Photo matching query does not exist. , Но это нормально, проблема в том, что я получаю неправильный ответ при попытке обработать эту ошибку. Ответ, который я получаю ( {'user': 'my username here'} ), относится self.data к сериализатору, если это поможет. Я не понимаю, почему это не дает ответной части except DoesNotExist:

Ответ №1:

Возможно, будет более понятно выполнить проверку в методе validate класса сериализатора. В случае отсутствия фотографии поднимите serializers.ValidationError свой .

Я не тестировал код, но думаю, что он работает.

 class LikeModelSerializer(serializers.ModelSerializer):
   
    ...

    def validate(self, attrs):
        photo_pk = self.context['view'].kwargs["photo_pk"]
        try:
            photo = Photo.objects.get(id=photo_pk)
        except Photo.DoesNotExist:
            raise serializers.ValidationError({"detail": "The photo doesn't exist"})
        attrs["photo"] = photo
        return attrs

    def create(self, validated_data):
        # Get the photo pk from the view context (DRF-nested-routers) and
        # create the new like with the validated_data
        like, created = Like.objects.get_or_create(**validated_data)
        if created:
            photo.total_likes  = 1
            photo.save()
        return like
 
 def perform_create(self, serializer):
    """ Creates a new like.

    The substraction in the total_likes is made in the serializer.
    """
    if not serializer.is_valid():
        raise ValidationError(serializer.errors)
    serializer.save()
    return Response(data=serializer.data, status=status.HTTP_200_OK)
 

Комментарии:

1. Это работает! Но мне нужно было добавить photo = Photo.objects.get(id=photo_pk) в метод создания, и он уже выполняет этот запрос validate() , есть идеи, как я могу сделать это только один раз? Например, может быть, просто войти validate() , а затем передать его методу создания?