如何在Django视图中显示PDF文件?

46

能否在Django视图中显示PDF文件而不是让用户下载查看?

如果可以的话,应该如何实现呢?

以下是我目前所拥有的 -

@login_required
def resume(request, applicant_id):

    #Get the applicant's resume
    resume = File.objects.get(applicant=applicant_id)
    fsock = open(resume.location, 'r')
    response = HttpResponse(fsock, mimetype='application/pdf')

    return response
12个回答

51

Django 有一个专门用于返回文件的类 FileResponse。它可以流式传输文件,因此您无需在返回文件之前将整个文件读入内存。以下是示例:

from django.http import FileResponse, Http404

def pdf_view(request):
    try:
        return FileResponse(open('foobar.pdf', 'rb'), content_type='application/pdf')
    except FileNotFoundError:
        raise Http404()
如果你有非常大的文件或者经常需要这样做,更好的选择可能是使用正常的服务器配置,在 Django 外部提供这些文件。

37

简单地说,如果您有一个PDF文件并想通过Django视图输出它,您需要做的就是将文件内容转储到响应中,并使用适当的MIME类型发送它。

def pdf_view(request):
    with open('/path/to/my/file.pdf', 'r') as pdf:
        response = HttpResponse(pdf.read(), mimetype='application/pdf')
        response['Content-Disposition'] = 'inline;filename=some_file.pdf'
        return response
    pdf.closed

你可能可以直接返回响应而不需要指定Content-Disposition,但是这样会更好地表明你的意图,并且还允许你在用户决定保存文件时指定文件名。

此外,请注意上面的代码无法处理不能打开或读取文件的情况。由于使用了with,它不会引发任何异常,但你仍然必须返回某种响应。你可以简单地引发一个Http404或其他异常。


3
直到我将 mimetype='application/pdf' 改为 contenttype='application/pdf',它才对我起作用。 - Andriy Ivaneyko
8
内容类型(content_type),同时pdf.closed在此处无效。 - amchugh89
2
@azuax 这是在上下文处理器中,难道不应该有 __exit__ 调用吗? - TankorSmash
最好使用rb而不是r,因为PDF文件不是文本文件。 - Flimm

16

PDF文件必须以rb而不是r的方式打开。

def pdf_view(request):
    with open('/path / to /name.pdf', 'rb') as pdf:
        response = HttpResponse(pdf.read(),content_type='application/pdf')
        response['Content-Disposition'] = 'filename=some_file.pdf'
        return response

使用'r'打开和显示PDF文件对我有效。 - yndolok
1
即使在非Windows机器上,最好使用rb而不是r,因为PDF文件不是文本文件。 - Flimm

8

在查看了@radtek上面的答案后,我决定研究基于类的视图显示。我尝试使用View,但它没有get_context_data()方法。

我在这里寻找一些指导。我选择了BaseDetailView,因为我只想显示一个对象。

from django.http import FileResponse
from django.shortcuts import get_object_or_404
from django.views.generic.detail import BaseDetailView

class DisplayPdfView(BaseDetailView):
    def get(self, request, *args, **kwargs):
        objkey = self.kwargs.get('pk', None) #1
        pdf = get_object_or_404(Pdf, pk=objkey) #2
        fname = pdf.filename() #3
        path = os.path.join(settings.MEDIA_ROOT, 'docs\\' + fname)#4
        response = FileResponse(open(path, 'rb'), content_type="application/pdf")
        response["Content-Disposition"] = "filename={}".format(fname)
        return response

评论

1 这行代码访问了通过调用视图的url传递的命名参数pk

2 这行代码获取了实际的pdf模型对象。

3 我在我的模型中定义了一个方法filename(self): return os.path.basename(self.file.name),以帮助我仅获取文件名和扩展名。

4 这行代码获取了完整的文件路径。

然后按照上面的答案使用文件响应。还要记得使用rb来读取pdf文件。


8

如果您想从服务器读取文件,请删除内联。此外,HttpResponse 的关键字参数 mimetype 已被替换为 content_type

(response['Content-Disposition'] = 'inline;filename=some_file.pdf')

def pdf_view(request):
    with open('/app/../Test.pdf', 'r') as pdf:
        response = HttpResponse(pdf.read(),content_type='application/pdf')
        response['Content-Disposition'] = 'filename=some_file.pdf'
        return response
    pdf.closed

4
这是一个典型的使用类视图显示PDF的用例:
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse

class DisplayPDFView(View):

    def get_context_data(self, **kwargs):  # Exec 1st
        context = {}
        # context logic here
        return context

    def get(self, request, *args, **kwargs):
        context = self.get_context_data()
        response = HttpResponse(content_type='application/pdf')
        response['Content-Disposition'] = 'inline; filename="worksheet_pdf.pdf"'  # Can use attachment or inline

        # pdf generation logic here
        # open an existing pdf or generate one using i.e. reportlab

        return response

# Remove login_required if view open to public
display_pdf_view = login_required(DisplayPDFView.as_view())

生成自己的pdf文件可以使用reportlab,具体细节请参考Django项目文档PDF生成
Chris Pratt提供了打开现有pdf文件的良好示例。

0

对我来说有效

import re, os
import os
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def export_auto_doc(request):
    name = request.GET.get('name', "")
    filename = "path/to/file"+name+".pdf"
    try:
        if not re.search("^[a-zA-Z0-9]+$",name):
            raise ValueError("Filename wrong format")
        elif not os.path.isfile(filename):
            raise ValueError("Filename doesn't exist")
        else:
            with open(filename, 'r') as pdf:
                response = HttpResponse(pdf.read(), content_type='application/pdf')
                response['Content-Disposition'] = 'inline;filename='+name+'.pdf'
                return response
            pdf.closed
    except ValueError as e:
        HttpResponse(e.message)

0
def pdf_view(request,pdfSlug):
     a = Pdf.objects.get(pdf_slug=pdfSlug)
     with open(str(a.pdf_file.path), 'rb') as pdf:
         response = FileResponse(pdf.read(), content_type='application/pdf')
         response['Content-Disposition'] = 'filename=a.pdf'
         return response
    pdf.closed

看这个,它对我起作用了。


0

最简单的方法可能是使用模板中的锚点。例如,如果您正在使用Django的模板引擎(大多数搜索此内容的人都是这样做的),只需通过锚点将其作为静态文件提供即可。

在包含指向该文件的链接的模板中,在顶部添加以下内容:

{% load static %}

然后,无论您想在哪里链接到您的pdf文件,请输入

<a href="{% static 'relative/path/file.pdf' %}">Click me</a>

第一行告诉Django在settings.py中配置的静态文件目录中查找。锚点标签中使用的路径是相对于在settings.py中配置为静态目录之一的任何目录的。当您单击呈现的链接时,只要您正确地设置了静态文件路径,它就应该在浏览器中显示PDF。


哦,我的错。这并没有完全回答问题。这不会在视图中显示PDF... - medley56

0

使用iframe url = pdf标记的url,并提供该pdf的url,确保您的用户对项目拥有完全控制权,然后pdf将显示在Web屏幕上


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接