Question :
Is it possible to show a PDF file in the Django view, rather than making the user have to download it to see it?
And if it is possible, how would it be done?
This is what I have so far –
@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
Answer #1:
Django has a class specifically for returning files, FileResponse. It streams files, so that you don’t have to read the entire file into memory before returning it. Here you go:
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()
If you have really large files or if you’re doing this a lot, a better option would probably be to serve these files outside of Django using normal server configuration.
Answer #2:
Simplistically, if you have a PDF file and you want to output it through a Django view, all you need to do is dump the file contents into the response and send it with the appropriate mimetype.
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
You can probably just return the response directly without specifying Content-Disposition, but that better indicates your intention and also allows you specify the filename just in case the user decides to save it.
Also, note that the view above doesn’t handle the scenario where the file cannot be opened or read for whatever reason. Since it’s done with with
, it won’t raise any exceptions, but you still must return some sort of response. You could simply raise an Http404
or something, though.
Answer #3:
If you are working on a Windows machine pdf must be opened as rb
not 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
Answer #4:
Take out inline; if you want your file to be read from server. And also, the HttpResponse
kwarg mimetype
has been replaced by 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
Answer #5:
Following @radtek’s answer above I decided to investigate a class-based view display. I tried to use View
but it didn’t have get_context_data()
method.
I looked here for some guidance. I settled for BaseDetailView
since I wanted to display just one object.
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
Commentary
1 This line accesses a named argument pk
passed by the url calling the view.
2 This line gets the actual pdf model object.
3 I defined a method filename(self): return os.path.basename(self.file.name)
in my model to help me get just the filename plus extension.
4 This line gets the complete filepath.
Then use file response as explained in the answers above. Also remember to use rb
to read the pdf file
Answer #6:
Here is a typical use-case for displaying a PDF using class-based views:
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())
For generating your own pdf with reportlab see the Django project Docs on PDF Generation.
Chris Pratt’s response shows a good example of opening existing PDFs.
Answer #7:
Browsers aren’t PDF readers (unless they have the proper plugin/addon).
You may want to render the PDF as HTML instead, which can be done from the backend or the frontend.
Answer #8:
it worked for me
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)