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
.
Ответы
Ответ 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
, вам повезет.