django-rest-framework
django-rest-framework copied to clipboard
DRF doesn't change the media type of request body to multipart/form-data automatically
Checklist
- [x] I have verified that that issue exists against the
masterbranch of Django REST framework. - [x] I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
- [x] This is not a usage question. (Those should be directed to the discussion group instead.)
- [x] This cannot be dealt with as a third party library. (We prefer new functionality to be in the form of third party libraries where possible.)
- [x] I have reduced the issue to the simplest possible case.
- [ ] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)
Steps to reproduce
# view.py
from rest_framework import generics
from rest_framework import serializers
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=200)
class BookSerializer(serializers.ModelSerializer):
cover = serializers.FileField()
class Meta:
model = Book
fields = ('cover',)
class BooksView(generics.CreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# urls.py
urlpatterns = [
...
path('api/books/', views.BooksView.as_view()),
...
]
Expected behavior
./manage.py generateschema
openapi: 3.0.2
info:
title: ''
version: TODO
paths:
/api/books/:
post:
operationId: CreateBook
parameters: []
requestBody:
content:
multipart/form-data:
schema:
required:
- cover
properties:
cover:
type: string
format: binary
responses:
'200':
content:
application/json:
schema:
required:
- cover
properties:
cover:
type: string
Actual behavior
./manage.py generateschema
openapi: 3.0.2
info:
title: ''
version: TODO
paths:
/api/books/:
post:
operationId: CreateBook
parameters: []
requestBody:
content:
application/json:
schema:
required:
- cover
properties:
cover:
type: string
responses:
'200':
content:
application/json:
schema:
required:
- cover
properties:
cover:
type: string
There are two things going on here:
- There is no support for automatic
multipart/form-datamedia type generation - The
FileFieldgenerates incomplete OpenAPI schema: it doesn't includeformat: binary. Finally, it should only generateformat: binaryfor requests, since you can't have a binary string field withinapplication/jsonmedia type. We could probably add aformat: uriin caseuse_url=True.
https://swagger.io/docs/specification/describing-request-body/multipart-requests/
On unrelated note I noticed that DRF doesn't put type: object under schema even though this spec passes validation here
Yeah seems valid to me. Of course it’s less obvious what we should do if we have both FileField and composite field types (that multipart can’t support.)
Could you please give an example of request body with file and composite field?
Eg. Anything with both FileField and DictField
Or FileField and a nested serializer
@knivets you fancy taking a pop at this? As Tom says, we should be able to do the simple cases at least.
(There may come a complexity level where we say “use a subclass to specify this particular case” rather than try and solve everything, but we’re not there yet...)
Yes! I’ll work on this over the weekend.
@knivets Do you have an idea what is the expected schema using OpenAPI Components ? Component's goal is to keep the same properties for request and response and reference them.
In the example you posted in "Expected behavior", the format: binary property is only in the "requestBody".
Should the schema include a different component for request and response?
I wasn't able to find any example about this on the web. Thanks!