Подтвердить что ты не робот

Django REST Framework + Django REST Swagger + ImageField

Я создал простую модель с ImageField, и я хочу сделать api-представление с django-rest-framework + django-rest-swagger, которое документировано и может загрузить файл.

Вот что я получил:

models.py

from django.utils import timezone
from django.db import models

class MyModel(models.Model):

    source = models.ImageField(upload_to=u'/photos')
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)

    def __unicode__(self):
        return u"photo {0}".format(self.source.url)

serializer.py

from .models import MyModel

class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        fields = [
            'id',
            'source',
            'created_at',
        ]

views.py

from rest_framework import generics
from .serializer import MyModelSerializer

class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FileUploadParser, )

    def post(self, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: source
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return super(MyModelView, self).post(self, *args, **kwargs)

urls.py

from weddings.api.views import MyModelView

urlpatterns = patterns(
    '',
    url(r'^/api/mymodel/$', MyModelView.as_view()),
)

Для меня это должно быть довольно просто. Однако я не могу сделать загрузку. Я всегда получаю этот ответ об ошибке: введите описание изображения здесь

Я прочитал эту часть документации из django-rest-framework:

If the view used with FileUploadParser is called with a filename URL keyword argument, then that argument will be used as the filename. If it is called without a filename URL keyword argument, then the client must set the filename in the Content-Disposition HTTP header. For example Content-Disposition: attachment; filename=upload.jpg.

Однако заголовок передается django-rest-swagger в свойстве Request Payload (из хром-консоли).

Если вам нужна дополнительная информация, пожалуйста, дайте мне знать.

Я использую Django==1.8.8, djangorestframework==3.3.2 и django-rest-swagger==0.3.4.

4b9b3361

Ответ 1

Это окончательное решение, с которым я пришел:

from rest_framework import generics
from rest_framework.parsers import FormParser, MultiPartParser
from .serializer import MyModelSerializer

class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FormParser, MultiPartParser)

    def post(self, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: source
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return super(MyModelView, self).post(self, *args, **kwargs)

Все, что мне нужно было сделать, это изменить парсеры от FileUploadParser до (FormParser, MultiPartParser)

Ответ 2

Я получил эту работу, сделав пару изменений в вашем коде.

Сначала в models.py измените имя ImageField на file и используйте относительный путь для загрузки папки. Когда вы загружаете файл в виде двоичного потока, он доступен в словаре request.data под ключом файла (request.data.get('file')), поэтому самый чистый вариант - сопоставить его с полем модели с тем же именем.

from django.utils import timezone
from django.db import models


class MyModel(models.Model):

    file = models.ImageField(upload_to=u'photos')
    is_active = models.BooleanField(default=False)
    created_at = models.DateTimeField(default=timezone.now)

    def __unicode__(self):
        return u"photo {0}".format(self.file.url)

В serializer.py переименуйте поле источника в файл:

class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        fields = ('id', 'file', 'created_at')

В views.py не вызывайте super, а вызывайте create():

from rest_framework import generics
from rest_framework.parsers import FileUploadParser

from .serializer import MyModelSerializer


class MyModelView(generics.CreateAPIView):
    serializer_class = MyModelSerializer
    parser_classes = (FileUploadParser,)

    def post(self, request, *args, **kwargs):
        """
            Create a MyModel
            ---
            parameters:
                - name: file
                  description: file
                  required: True
                  type: file
            responseMessages:
                - code: 201
                  message: Created
        """
        return self.create(request, *args, **kwargs)

Я использовал расширение Postman Chrome для проверки этого. Я загрузил изображения в виде двоичных файлов, и я вручную установил два заголовка:

Content-Disposition: attachment; filename=upload.jpg
Content-Type: */*

Ответ 3

По моему опыту, FileUploadParser работает с этим форматом запроса:

    curl -X POST -H "Content-Type:multipart/form-data" \
                 -F "[email protected]{filename};type=image/jpg" \
                 https://endpoint.com/upload-uri/

request.data['file'] в вашем представлении будет иметь файл.

Возможно, если вы попробуете заголовок Content-Type:multipart/form-data, вам повезет.