I created a simple Model with an ImageField and I wanna make an api view with django-rest-framework + django-rest-swagger, that is documented and is able to upload the file.
Here is what I got:
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()),
)
For me this should be pretty simple. However, I can't make the upload work. I always get this error response:
I've read this part of the documentation from 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.
However the Header is being passed by django-rest-swagger in the Request Payload property (from chrome console).
If any more info is necessary, please let me know.
I'm using Django==1.8.8
, djangorestframework==3.3.2
and django-rest-swagger==0.3.4
.
Improved performance. Allow multiple instances of Swagger UI in a single Django project. Allow rendering the OpenAPI JSON spec independently. Improved control of authentication mechanisms.
drf-yasg is a Swagger generation tool implemented without using the schema generation provided by Django Rest Framework. It aims to implement as much of the OpenAPI specification as possible - nested schemas, named models, response bodies, enum/pattern/min/max validators, form parameters, etc.
Django REST Swagger: deprecated (2019-06-04) This project is no longer being maintained.
Django REST framework is a powerful and flexible toolkit for building Web APIs. Some reasons you might want to use REST framework: The Web browsable API is a huge usability win for your developers. Authentication policies including packages for OAuth1a and OAuth2.
I got this working by making a couple of changes to your code.
First, in models.py
, change ImageField
name to file
and use relative path to upload folder. When you upload file as binary stream, it's available in request.data
dictionary under file key (request.data.get('file')
), so the cleanest option is to map it to the model field with the same name.
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)
In serializer.py
, rename source field to file:
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('id', 'file', 'created_at')
In views.py, don't call super, but call 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)
I've used Postman Chrome extension to test this. I've uploaded images as binaries and I've manually set two headers:
Content-Disposition: attachment; filename=upload.jpg
Content-Type: */*
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With