2016-04-18 7 views
17

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

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

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()), 
) 

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

Я прочитал эту часть документации из 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.

Однако заголовок идет мимо Джанго-покоя развязность в Payload Запрос свойство (из хром-консоли).

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

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

+0

ли вы установили подушку? Я считаю, что django rest нуждается в обработке файлов изображений. https://pypi.python.org/pypi/Pillow –

+0

Спасибо, Чарльз .. но да, у меня есть Подушка установлена. – jarussi

ответ

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)

+0

Что вам нужно сделать, чтобы заставить DRF или DRF-Swagger забрать этот yml? Я установил docstring как это, но он просто отображает как Markdown в разделе «Замечания по реализации» –

+0

У меня не так много в моих настройках. Я в значительной степени основной из документов django-rest-swagger. Тем не менее, я использую версию '0.3.7' django-rest-swagger. – jarussi

7

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

Прежде всего, в 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, не называют супер, но назвать создание():

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: */* 
+0

Я попробовал изменения, которые вы предложили, но теперь я испытываю другую ошибку: 'Загрузите действительное изображение. Загруженный вами файл был либо не изображением, либо поврежденным изображением. – jarussi

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'] в вашем view будет иметь файл.

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

+0

Спасибо, zemekeneng, но я до сих пор получаю и ошибки: '{" file ": [" Представленный файл пуст. "]}'. Это не сработало. – jarussi

+0

Возможно, попробуйте называть его 'curl' и убедитесь, что имя файла находится внутри' {} ', поэтому оно выглядит как' file = @ {path/to/file} ', если это работает, тогда проблема может быть клиентом -боковая сторона. Удачи! – zemekeneng

Смежные вопросы