Django Rest Framework File Upload API
Posted by Vivek Shukla on Jun 21, 2023 under Django Rest Framework
Uploading file via API is a very common requirement. In this guide we will learn to build Django Rest Framework File Upload API.
Table of Contents
Setup
Django: 4.2
Django Rest Framework: 3.14.0
Project Name:
fileupload
App Name:
api
Add your app in INSTALLED_APPS
In fileupload/settings.py
INSTALLED_APPS = [
.....
'rest_framework',
'api', # your django app
]
Update MEDIA path in settings.py
We need to set the path where we want the uploaded files to be stored.
In settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
Update project’s urls.py file
For Django to be able to serve media files we need to enable this using static
helper function that Django provides. This only works in DEBUG mode and only if folder location is local. source
In fileupload/urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('api.urls', namespace='api')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Model
Let’s create a Model where we store the file path (as file
) and file upload time (as uploaded_on
). So the uploaded file will be stored in media
folder and file
field will contain it’s path.
In your api/models.py
class UploadedFile(models.Model):
file = models.FileField()
uploaded_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.uploaded_on.date()
Run the migration
python manage.py makemigrations
python manage.py migrate
Serializer
Creating a ModelSerializer for our Model UploadedFile
. ModelSerializer creates serializer fields based on Model passed and comes with buil-in save
method that saves passed data into database.
In your api/serializers.py
from rest_framework import serializers
from .models import UploadedFile
class FileUploadSerializer(serializers.ModelSerializer):
class Meta:
model = UploadedFile
fields = ('file', 'uploaded_on',)
View
Now we create the view class FileUploadAPIView
(sub-class of APIView) to save the uploaded file. Few things to note:
Generally the
JSONParser
is set as the default parser in DRF so that we can send the request in JSON format. However it is not advised/convenient to upload file in JSON.form-data
is the best way to upload the file, to enable this we need to passMultiPartParser
andFormParser
as ourparser_classes
in our view.Only
MultiPartParser
can be passed to enable file uploading but as per DRF API Guide on MultiPartParser, we should use both parser classes to fully support HTML form data.
In api/views.py
from rest_framework import status
from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import FileUploadSerializer
class FileUploadAPIView(APIView):
parser_classes = (MultiPartParser, FormParser)
serializer_class = FileUploadSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
# you can access the file like this from serializer
# uploaded_file = serializer.validated_data["file"]
serializer.save()
return Response(
serializer.data,
status=status.HTTP_201_CREATED
)
return Response(
serializer.errors,
status=status.HTTP_400_BAD_REQUEST
)
Urls
Let’s connect our view in urls to be able to receive requests on it.
In api/urls.py
from django.urls import path
from .views import FileUploadAPIView, ImageUploadAPIView
app_name = 'api'
urlpatterns = [
path('upload-file/', FileUploadAPIView.as_view(), name='upload-file'),
]
Testing API Endpoint
Start the server
python manage.py runserver
Postman
Method: POST (as per our view)
URL: http://localhost:8000/api/upload-file/
Body Type: form-data
Values to be passed
- file as KEY (change the type to File in dropdown), Browse and select a file for VALUE
cURL
curl --location --request POST 'http://localhost:8000/api/upload-file/' --form 'file=@"/path/to/yourfile.pdf"'
NodeJS - Axios
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
data.append('file', fs.createReadStream('/path/to/yourfile.pdf'));
var config = {
method: 'post',
url: 'http://localhost:8000/api/upload-file/',
headers: {
...data.getHeaders(),
},
data: data,
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
Checkout this guide to learn how to store static and media files in AWS S3