Anti
Anti

Reputation: 141

How to return a file from django API which was saved in a mongodb?

I am struggeling to return a file e.g. a pdf which was uploaded to a mongodb. I am able to upload a file to the database but I am not able to retrieve the file again. How shoud my endpoint (view) look like to return the file? I am using django rest framework v3.12.4 with djongo v1.3.6. I use drf-yasg v1.20.0 for the documentation of the API. Here are my settings, models.py, serializers.py, views.py and urls.py:

# app settings.py
DATABASES = {
    'default': {
            'ENGINE': 'djongo',
            'NAME': 'TAST_DB2',
            'CLIENT': {
                'host': 'localhost',
                'port': 27017,
                'username': 'root',
                'password': 'reallychangeme',        # :-)
                'authSource': 'admin',
                'authMechanism': 'SCRAM-SHA-1'
            } 
        }
}
DEFAULT_FILE_STORAGE = 'mongo_storage.storage.GridFSStorage'
GRIDFS_DATABASE = 'myfiles'
BASE_URL = 'http://localhost:8085/'
UPLOADED_FILES_USE_URL = True

# models.py
from django.db import models
from djongo.storage import GridFSStorage

grid_fs_storage = GridFSStorage(collection='myfiles', base_url=''.join([settings.BASE_URL, 'myfiles/']))

class TestStandardFile(models.Model):
    myfile = models.FileField(upload_to='teststandards1', storage=grid_fs_storage)

# serializers.py
from rest_framework import serializers 
from teststandards.models import TestStandardFile

class TestStandardFileSerializer(serializers.ModelSerializer):
    class Meta:
        model = TestStandardFile
        fields = '__all__'

# views.py
from rest_framework.generics import ListCreateAPIView
from .models import TestStandard
from .serializers import TestStandardFileSerializer
from rest_framework.parsers import MultiPartParser

# used for the upload
class FileView(ListCreateAPIView):
    parser_classes = ( MultiPartParser,)
    serializer_class = TestStandardFileSerializer
    queryset = TestStandardFile.objects.all()

<----------      !ENDPOINT FOR FILE RETRIEVAL MISSING HERE???

# urls.py
urlpatterns = [ 
   re_path(r'^api/teststandards/file', api.FileView.as_view(), name='teststandard-file'),
   re_path(r'^myfiles/(?P<pk>[0-9]+)$', api.myfiles.as_view(), name='get-file'),
]

I can see my file properly uploaded to mongodb with mongodb compass. There are three collections in it:

  1. TAST_DB2.teststandardsFiles
  2. TAST_DB2.myfiles.teststandards1.files
  3. TAST_DB2.myfiles.teststandards1.chunks

I assume that I need an endpoint which gives the file back as a response. I tried to overwrite the 'get'-function of my 'myfiles' endpoint. But I don't know how to get the file handle from the requested file. And I do not know how to return the file as a HttpResponse.

Any help is appreciated!

Upvotes: 2

Views: 1439

Answers (1)

Anti
Anti

Reputation: 141

I finally got it to work. I created an RetrieveAPIView for the retrieval of one entry and overwrote the retrieve function. THis is how my views.py looked like:

    # for upload
    class FileView(ListCreateAPIView):
        parser_classes = ( MultiPartParser,)
        serializer_class = TestStandardFileSerializer
        queryset = TestStandardFile.objects.all()
    
    # download
    class myfiles(RetrieveAPIView):
        parser_classes = ( MultiPartParser,)
        serializer_class = TestStandardFileSerializer
        queryset = TestStandardFile.objects.all()
    
        def retrieve(self, request, *args, **kwargs):
            obj = self.get_object()        
            response = HttpResponse(obj.myfile, content_type='application/octet-stream')
            response['Content-Disposition'] = 'attachment; filename=%s' % obj.myfile
            return response

"myfile" is the name of the FileField from my model. With using drf_spectacular for the swagger documentation. This generated a nice download button for the file retrieval. It helped a lot during testing the upload / download functionality.

Upvotes: 1

Related Questions