9

I have a Django REST Framework project which uses a ModelViewSet to create APIs for a model containing a FileField.

I've shared a full example of a Django project demonstrating this issue here. But to summarise the key components:

models.py

from django.db import models


class Profile(models.Model):
    image = models.FileField(upload_to='uploads/%Y/%m/%d/')

views.py

from rest_framework import (
    viewsets,
    serializers,
    parsers,
)

from sample import models


class ProfileSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.Profile
        fields = ['id', 'image']
        read_only_fields = ['id']


class ProfileViewSet(viewsets.ModelViewSet):
    serializer_class = ProfileSerializer
    queryset = models.Profile.objects.all()

urls.py

from drf_spectacular.views import (
    SpectacularAPIView,
    SpectacularSwaggerView,
)

from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings

from rest_framework.routers import DefaultRouter

from sample import views


router = DefaultRouter()
router.register('profile', views.ProfileViewSet)


urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/schema/', SpectacularAPIView.as_view(), name='api-schema'),
    path(
        'api/docs/',
        SpectacularSwaggerView.as_view(url_name='api-schema'),
        name='api-docs',
    ),
    path('', include(router.urls)),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py (REST_FRAMEWORK configuration only):

REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

requirements.txt

Django==3.2.3
djangorestframework==3.12.4
drf-spectacular==0.16.0

I am generating browsable Swagger-UI docs using drf-spectacular to document the API.

The problem is that the FileField input in Swagger-UI is a string input, and doesn't give the option to set a file:

enter image description here

I would like to have a file input where I can choose a file which will be sent to the API.

My question is: How can I configure DRF or drf-spectacular to show this field?

JPG
  • 82,442
  • 19
  • 127
  • 206
LondonAppDev
  • 8,501
  • 8
  • 60
  • 87

1 Answers1

21

After some digging through the drf-spectacular docs and GitHub issues, I found that the FileField can be set to binary by adding the following to in settings.py:

SPECTACULAR_SETTINGS = {
    'COMPONENT_SPLIT_REQUEST': True
}

Also in Swagger UI, make sure you change the content-type from application/json to multipart/form-data and click Try it out. The upload button will apppear.

LondonAppDev
  • 8,501
  • 8
  • 60
  • 87
  • 1
    @JPG thanks for the update... For me it's working with `REST_FRAMEWORK`. What's the reason for changing it to `SPECTACULAR_SETTINGS`? – LondonAppDev May 14 '21 at 12:26
  • btw, the official [DRF settings](https://www.django-rest-framework.org/api-guide/settings/) doesn't contain `COMPONENT_SPLIT_REQUEST` but in the [drf-spectacular](https://drf-spectacular.readthedocs.io/en/latest/settings.html) settings – JPG May 14 '21 at 12:30
  • 2
    @JPG just tested on my project and it definitely works if I put `COMPONENT_SPLIT_REQUESTS` inside `REST_FRAMEWORK`. Didn't see anything in the docs, but my guess is that it falls back to use `REST_FRAMEWORK` settings if `SPECTACULAR_SETTINGS` isn't defined. However docs do state that it should be put in `SPECTACULAR_SETTINGS` so I think your edit did improve the answer. Thank you! – LondonAppDev May 14 '21 at 14:59
  • That's weird. I would like to do some digging into the problem. Could you share the minimal project or create another branch in [this repo](https://github.com/LondonAppDev/drf-openapi-filefield-issue) to have a closer look? – JPG May 14 '21 at 15:12
  • `SPECTACULAR_SETTINGS` that are falsely put into `REST_FRAMEWORK` are not honored. drf-spectacular will not look there for its own settings. – Insa Aug 31 '23 at 09:30