How to return generated file download with Django REST Framework?

后端 未结 5 1308
清歌不尽
清歌不尽 2021-02-04 03:20

I need to return generated file download as a Django REST Framework response. I tried the following:

def retrieve(self, request, *args, **kwargs):
    template =         


        
相关标签:
5条回答
  • 2021-02-04 04:06

    For me, using Python 3.6, Django 3.0, and DRF 3.10, The problem came from using the wrong type of response. I needed to use a django.http.HttpResponse, as seen below:

    from django.http import HttpResponse
    ...
    with open('file.csv', 'r') as file:
        response = HttpResponse(file, content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename=file.csv'
        return response
    
    0 讨论(0)
  • 2021-02-04 04:19

    I am using DRF and i found a view code to download file, which would be like

    from rest_framework import generics
    from django.http import HttpResponse
    from wsgiref.util import FileWrapper
    
    class FileDownloadListAPIView(generics.ListAPIView):
    
        def get(self, request, id, format=None):
            queryset = Example.objects.get(id=id)
            file_handle = queryset.file.path
            document = open(file_handle, 'rb')
            response = HttpResponse(FileWrapper(document), content_type='application/msword')
            response['Content-Disposition'] = 'attachment; filename="%s"' % queryset.file.name
            return response
    

    and url.py will be

    path('download/<int:id>/',FileDownloadListAPIView.as_view())
    

    I am using React.js in frontend and i get a response like

    handleDownload(id, filename) {
      fetch(`http://127.0.0.1:8000/example/download/${id}/`).then(
        response => {
          response.blob().then(blob => {
          let url = window.URL.createObjectURL(blob);
          let a = document.createElement("a");
          console.log(url);
          a.href = url;
          a.download = filename;
          a.click();
        });
      });
    }
    

    and after i got successful in downloading a file which also opens correctly and i hope this gonna work. Thanks

    0 讨论(0)
  • 2021-02-04 04:25

    Here's an example of returning a file download directly from DRF. The trick is to use a custom renderer so you can return a Response directly from the view:

    from django.http import FileResponse
    from rest_framework import viewsets, renderers
    from rest_framework.decorators import action
    
    class PassthroughRenderer(renderers.BaseRenderer):
        """
            Return data as-is. View should supply a Response.
        """
        media_type = ''
        format = ''
        def render(self, data, accepted_media_type=None, renderer_context=None):
            return data
    
    class ExampleViewSet(viewsets.ReadOnlyModelViewSet):
        queryset = Example.objects.all()
    
        @action(methods=['get'], detail=True, renderer_classes=(PassthroughRenderer,))
        def download(self, *args, **kwargs):
            instance = self.get_object()
    
            # get an open file handle (I'm just using a file attached to the model for this example):
            file_handle = instance.file.open()
    
            # send file
            response = FileResponse(file_handle, content_type='whatever')
            response['Content-Length'] = instance.file.size
            response['Content-Disposition'] = 'attachment; filename="%s"' % instance.file.name
    
            return response
    

    Note I'm using a custom endpoint download instead of the default endpoint retrieve, because that makes it easy to override the renderer just for this endpoint instead of for the whole viewset -- and it tends to make sense for list and detail to return regular JSON anyway. If you wanted to selectively return a file download you could add more logic to the custom renderer.

    0 讨论(0)
  • 2021-02-04 04:25

    This may work for you:

    file_path = file_url
    FilePointer = open(file_path,"r")
    response = HttpResponse(FilePointer,content_type='application/msword')
    response['Content-Disposition'] = 'attachment; filename=NameOfFile'
    
    return response.
    

    For FrontEnd code refer this

    0 讨论(0)
  • 2021-02-04 04:25

    I solved my problem by saving file in media folder and sending of the link of it to front-end.

    @permission_classes((permissions.IsAdminUser,))
    class StudentDocxViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
        def retrieve(self, request, *args, **kwargs):
            template = webodt.ODFTemplate('test.odt')
            queryset = Pupils.objects.get(id=kwargs['pk'])
            serializer = StudentSerializer(queryset)
            context = dict(serializer.data)
            document = template.render(Context(context))
            doc = converter().convert(document, format='doc')
            p = u'docs/cards/%s/%s_%s.doc' % (datetime.now().date(), context[u'surname'], context[u'name'])
            path = default_storage.save(p, doc)
            return response.Response(u'/media/' + path)
    

    And handled this like in my front-end (AngularJS SPA)

    $http(req).success(function (url) {
        console.log(url);
        window.location = url;
    })
    
    0 讨论(0)
提交回复
热议问题