如何使用Django REST Framework返回生成的文件下载?

Vik*_*tor 13 python django ms-word download django-rest-framework

我需要将生成的文件下载作为Django REST Framework响应返回.我尝试了以下方法:

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')
    res = HttpResponse(
        FileWrapper(doc),
        content_type='application/msword'
    )
    res['Content-Disposition'] = u'attachment; filename="%s_%s.zip"' % (context[u'surname'], context[u'name'])
    return res
Run Code Online (Sandbox Code Playgroud)

但它返回一个msword文档json.

如何让它开始下载为文件?

小智 10

我正在使用 DRF,我找到了一个查看代码来下载文件,这就像

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
Run Code Online (Sandbox Code Playgroud)

和 url.py 将是

path('download/<int:id>/',FileDownloadListAPIView.as_view())
Run Code Online (Sandbox Code Playgroud)

我在前端使用 React.js,得到如下响应

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();
    });
  });
}
Run Code Online (Sandbox Code Playgroud)

在我成功下载一个文件后,该文件也可以正确打开,我希望这能起作用。谢谢


Piy*_*are 8

这可能对你有用:

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

return response.
Run Code Online (Sandbox Code Playgroud)

对于前端代码是指

  • 它应该是:'response = HttpResponse(FilePointer.read(),content_type ='application/msword')' (2认同)

Jac*_*man 6

这是直接从DRF返回文件下载的示例。诀窍是使用自定义渲染器,以便您可以直接从视图返回响应:

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
Run Code Online (Sandbox Code Playgroud)

请注意,我使用的是自定义终结点download而不是默认终结点retrieve,因为这样可以轻松地仅针对此终结点而不是整个视图集覆盖渲染器,无论如何,列表和详细信息无论如何都会返回常规JSON 。如果要有选择地返回文件下载,可以向自定义渲染器添加更多逻辑。


小智 6

对于我来说,使用 Python 3.6、Django 3.0 和 DRF 3.10,问题来自于使用了错误的响应类型。我需要使用 a django.http.HttpResponse,如下所示:

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
Run Code Online (Sandbox Code Playgroud)


Vik*_*tor 4

我通过将文件保存在媒体文件夹中并将其链接发送到前端来解决我的问题。

@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)
Run Code Online (Sandbox Code Playgroud)

并像在我的前端(AngularJS SPA)中一样处理这个问题

$http(req).success(function (url) {
    console.log(url);
    window.location = url;
})
Run Code Online (Sandbox Code Playgroud)