繁体   English   中英

如何使用 django rest 框架发送文件作为响应?

[英]How do I use django rest framework to send a file in response?

我需要发送一个 pdf 文件和一些其他参数来响应使用 django rest 框架的 get API 调用。

我该怎么做? 我试过了,但它给出了一个错误<django.http.HttpResponse object at 0x7f7d32ffafd0> is not JSON serializable

@detail_route(methods=['get'])
def fetch_report(self, request, *args, **kwargs):
    short_report = open("somePdfFile", 'rb')
    response = HttpResponse(FileWrapper(short_report), content_type='application/pdf')
    return Response({'detail': 'this works',
        'report': response})

这里的问题是您试图返回 JSON 和 PDF 的混合,这要么不是您要查找的内容,要么将返回一个巨大的base64 编码响应。 PDF 是一种二进制格式而 JSON 是一种文本格式,您无法真正将它们混合在一起。

在 DRF 视图中,您可以直接返回一个 Django 响应,您似乎已经在生成它( HttpResponse ),DRF 将通过它并跳过渲染器。 这在这种情况下很有用,因为它允许您返回二进制响应,例如图像或 PDF,而不必担心 DRF 的渲染层会导致问题。

@detail_route(methods=['get'])
def fetch_report(self, request, *args, **kwargs):
    short_report = open("somePdfFile", 'rb')
    response = HttpResponse(FileWrapper(short_report), content_type='application/pdf')
    return response

另一种方法是使用base64 encoding 之类的东西将 PDF 编码为文本。 这将大大增加您的响应大小,但它可以让您毫无问题地使用 DRF 的渲染层。

@detail_route(methods=['get'])
def fetch_report(self, request, *args, **kwargs):
    import base64
    short_report = open("somePdfFile", 'rb')
    report_encoded = base64.b64encode(short_report.read())
    return Response({'detail': 'this works',
        'report': report_encoded})

但我在这里推荐的方法是生成 PDF 并将其存储在您的媒体存储或其他私人位置,并在您的回复中提供指向它的直接链接。 这样就不用担心编码问题,不用直接返回PDF,不用担心直接提供PDF。

如果您真的需要直接从后端提供二进制文件(例如,动态生成它们时),您可以使用自定义渲染器

from rest_framework.renderers import BaseRenderer

class BinaryFileRenderer(BaseRenderer):
    media_type = 'application/octet-stream'
    format = None
    charset = None
    render_style = 'binary'

    def render(self, data, media_type=None, renderer_context=None):
        return data

然后在视图集中的操作中使用它:

@detail_route(methods=['get'], renderer_classes=(BinaryFileRenderer,))
def download(self, request, *args, **kwargs):
    with open('/path/to/file.pdf', 'rb') as report:
        return Response(
            report.read(),
            headers={'Content-Disposition': 'attachment; filename="file.pdf"'},
            content_type='application/pdf')

您可以将DRF-PDF项目与PDFFileResponse一起使用

from rest_framework import status
from rest_framework.views import APIView
from drf_pdf.response import PDFFileResponse
from drf_pdf.renderer import PDFRenderer


class PDFHandler(APIView):

    renderer_classes = (PDFRenderer, )

    def get(self, request):
        return PDFFileResponse(
            file_path='/path/to/file.pdf',
            status=status.HTTP_200_OK
        )

但是,也许您不能以两种格式(json 和流)响应。

您可以发送 pdf 文件作为对任何请求的响应,而无需安装任何软件包。

您可以执行以下操作。

def get(request, *args, **kwargs):
    # some code
    # some code

    with fs.open("path/to/file/Report.pdf") as pdf:
        response = HttpResponse(pdf, content_type='application/pdf')
        filename = "Report.pdf"
        response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)

        return response

现在,打开您的postman并点击get/post请求。

重要提示:在邮递员中单击send按钮之前,请选择选项send and download

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM