我需要将生成的文件下载作为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
但它会将msword文档作为json
返回。
如何让它开始以文件形式下载?
答案 0 :(得分:6)
这可能对您有用:
file_path = file_url
FilePointer = open(file_path,"r")
response = HttpResponse(FilePointer,content_type='application/msword')
response['Content-Disposition'] = 'attachment; filename=NameOfFile'
return response.
对于FrontEnd代码,请参阅this
答案 1 :(得分:2)
这里是直接从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
请注意,我使用的是自定义端点download
而不是默认端点retrieve
,因为这样可以轻松地仅针对此端点而不是整个视图集覆盖渲染器-并且无论如何,列表和详细信息无论如何返回常规JSON都是有意义的。如果要有选择地返回文件下载,可以向自定义渲染器添加更多逻辑。
答案 2 :(得分:1)
我通过将文件保存在媒体文件夹中并将其链接发送到前端来解决了我的问题。
@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)
并在我的前端(AngularJS SPA)处理此问题
$http(req).success(function (url) {
console.log(url);
window.location = url;
})
答案 3 :(得分:1)
我正在使用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
和url.py将是
path('download/<int:id>/',FileDownloadListAPIView.as_view())
我在前端使用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();
});
});
}
,在我成功下载了也可以正确打开的文件后,我希望它能工作。谢谢
答案 4 :(得分:0)
对我来说,使用Python 3.6,Django 3.0和DRF 3.10,问题出在使用错误的响应类型。我需要使用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