Загрузка файла с помощью инфраструктуры Django REST ListCreateAPIView

Используя Django REST framework generic ListCreateAPIView, я создал конечную точку, которая, я думаю, должна иметь возможность загружать фотографии через запросы POST. Я моделирую свой код этот учебник.

До сих пор я пытался отправить файл POST на эту конечную точку, используя как Android, так и curl, и наблюдал такое же поведение: создается новая запись, но файл не подключен. Поскольку файл является обязательным, сервер затем возвращает ошибку 500.

Этот вопрос выглядит примерно так, но он не использует общие ракурсы REST, и я не уверен, почему... Я хотел бы воспользоваться ими, где применимо.

Вот мой взгляд Django:

class PhotoList(generics.ListCreateAPIView):
    model = Photo
    serializer_class = PhotoSerializer
    permission_classes = [
        permissions.AllowAny
    ]

... моя модель:

def get_unique_image_file_path(instance=None, filename='dummy.jpg'):
    """
    function to determine where to save images.  assigns a uuid (random string) to each and places it
    in the images subdirectory below media.  by default, we assume the file is a .jpg
    """
    ext = filename.split('.')[-1]
    filename = "%s.%s" % (uuid.uuid4(), ext)
    # TODO: 'images' is hard coded
    return os.path.join('images', filename)

class Photo(models.Model):
    post = models.ForeignKey(Post, related_name='photos', null=True, blank=True)
    image = models.ImageField(upload_to=get_unique_image_file_path)

    def get_image_abs_path(self):
        return os.path.join(settings.MEDIA_ROOT, self.image.name)

... и мой сериализатор:

class PhotoSerializer(serializers.ModelSerializer):
    image = serializers.Field('image.url')

class Meta:
    model = Photo

Воспроизведение ошибки

Чтобы сгенерировать поведение, я отправляю сообщение на сервер с помощью следующей команды curl (точно так же происходит с моим кодом клиента Android):

curl --form [email protected]_image.jpg http://localhost:8000/rest_tutorial/photos

В generics.ListCreateAPIView метод create() выглядит следующим образом:

# Copied from rest_framework.mixins.CreateModelMixin 

def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.DATA, files=request.FILES)

    if serializer.is_valid():
        self.pre_save(serializer.object)
        self.object = serializer.save(force_insert=True)
        self.post_save(self.object, created=True)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED,
                        headers=headers)

    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Когда я перехожу через указанный выше код в отладчике PyCharm, я могу отчетливо видеть мой файл в поле serializer init_files после serializer.get_serializer(). Однако в поле serializer object есть куча трассировок, но ссылки на мой файл изображения отсутствуют. Может, здесь что-то не так?

После self.object = serializer.save(force_insert=True) запись создается с пустым полем изображения, файл не загружается, а self.object.image.file просто содержит трассировку, обратную к ValueError.

Любые идеи? Спасибо!

Ответ 1

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

class PhotoSerializer(serializers.ModelSerializer):

    class Meta:
        model = Photo

Надеюсь, что это поможет, дайте мне знать, как вы ладите.