Django REST Framework + Django REST Swagger + ImageField

19

Я создал простую модель с помощью 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 (из консоли chrome).

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

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

    
задан jarussi 18.04.2016 в 20:42
источник
  • У вас установлена ​​подушка? Я считаю, что django rest нуждается в обработке файлов изображений pypi.python.org/pypi/Pillow –  Charles Haro 22.04.2016 в 19:59
  • Спасибо, Чарльз .. но да, у меня есть Подушка установлена. –  jarussi 24.04.2016 в 02:34

3 ответа

3

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

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)

    
ответ дан jarussi 10.06.2016 в 19:59
  • Что вам нужно сделать, чтобы заставить DRF или DRF-Swagger забрать этот yml? Я установил такую ​​docstring, но он просто отображается как Markdown в разделе «Замечания по реализации», –  Aaron McMillin 17.05.2017 в 15:24
  • У меня не так много в моих настройках. Я в значительной степени основной из документов django-rest-swagger. Тем не менее, я использую версию 0.3.7 django-rest-swagger. –  jarussi 01.06.2017 в 14:44
8

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

Сначала в 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: */*
    
ответ дан ozren1983 27.04.2016 в 00:01
  • Я попробовал изменения, которые вы предложили, но теперь я испытываю другую ошибку: Загрузите действительное изображение. Загруженный вами файл был либо не изображением, либо поврежденным изображением –  jarussi 28.04.2016 в 23:03
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 , вам повезет.

    
ответ дан zemekeneng 27.04.2016 в 00:09
  • Спасибо, zemekeneng, но я все равно получаю и ошибки: {"file": ["Представленный файл пуст."]}. Это не сработало. –  jarussi 28.04.2016 в 22:42
  • Возможно, попробуйте вызвать его с помощью curl и убедитесь, что имя файла находится внутри {}, поэтому оно выглядит как file = @ {path / to / file}, если это работает, тогда проблема может быть на стороне клиента. Удачи! –  zemekeneng 28.04.2016 в 23:13