¿Cómo mostrar un archivo PDF en una vista de Django?

¿Es posible mostrar un archivo PDF en la vista Django, en lugar de hacer que el usuario tenga que descargarlo para verlo?

Y si es posible, ¿cómo se haría?

Esto es lo que tengo hasta ahora –

@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 

De manera simplista, si tiene un archivo PDF y desea imprimirlo a través de una vista de Django, todo lo que necesita hacer es volcar el contenido del archivo en la respuesta y enviarlo con el tipo de mímeto apropiado.

 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 

Probablemente, solo puede devolver la respuesta directamente sin especificar la Disposición del contenido, pero eso indica mejor su intención y también le permite especificar el nombre del archivo en caso de que el usuario decida guardarlo.

Además, tenga en cuenta que la vista anterior no controla el escenario donde el archivo no se puede abrir o leer por cualquier motivo. Ya que se terminó con, no generará ninguna excepción, pero aún así debe devolver algún tipo de respuesta. Sin embargo, simplemente puedes subir un Http404 o algo así.

Django tiene una clase específica para devolver archivos, FileResponse . Transmite archivos para que no tenga que leer todo el archivo en la memoria antes de devolverlo. Aqui tienes:

 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() 

Si tiene archivos realmente grandes o si lo está haciendo mucho, probablemente una mejor opción sería publicar estos archivos fuera de Django usando la configuración normal del servidor.

Si está trabajando en una máquina con Windows, el pdf debe abrirse como rb no 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 

Sacar en línea; Si quieres que tu archivo sea leído desde el servidor. Y también, el mimetype kwarg HttpResponse ha sido reemplazado por 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 

Siguiendo la respuesta de @radtek anterior, decidí investigar una visualización de vista basada en clase. Intenté usar View pero no tenía el método get_context_data() .

Busqué aquí una guía. Me conformé con BaseDetailView porque quería mostrar solo un objeto.

 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 

Comentario

1 Esta línea accede a un argumento con nombre pk pasado por la url que llama a la vista.

2 Esta línea obtiene el objeto de modelo pdf real.

3 filename(self): return os.path.basename(self.file.name) un método de filename(self): return os.path.basename(self.file.name) en mi modelo para ayudarme a obtener solo el nombre de archivo más la extensión.

4 Esta línea recibe la ruta de archivo completa.

Luego use la respuesta del archivo como se explica en las respuestas anteriores. También recuerda usar rb para leer el archivo pdf

Este es un caso de uso típico para mostrar un PDF utilizando vistas basadas en clases:

 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 ie reportlab return response # Remove login_required if view open to public display_pdf_view = login_required(DisplayPDFView.as_view()) 

Para generar su propio pdf con reportlab, vea los documentos del proyecto Django sobre la generación de PDF .

La respuesta de Chris Pratt muestra un buen ejemplo de cómo abrir archivos PDF existentes.

Los navegadores no son lectores de PDF (a menos que tengan el complemento / complemento adecuado).

Es posible que desee renderizar el PDF como HTML, lo que se puede hacer desde el backend o el frontend .

funciono para mi

 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) 

Solo estoy tirando esto por ahí.

Simplemente puede agregar su currículum vitae PDF a sus archivos estáticos.

Si está utilizando White Noise para servir sus archivos estáticos, entonces ni siquiera necesita hacer la vista. Solo entonces accede a tu currículum en la ubicación estática.

Agregué el mío, aquí está: https://www.jefferythewind.com/static/main/resume/TIm-D_Nice.pdf

Advertencia: Esto no resuelve el requisito login_required en la pregunta

La forma más fácil de hacer esto es probablemente con un ancla en una plantilla. Por ejemplo, si está utilizando el motor de plantillas de Django (como es probable que la mayoría de las personas que buscan esto) lo sirvan como un archivo estático a través de un ancla.

En su plantilla que contendrá un enlace al archivo, agregue en la parte superior

 {% load static %} 

Entonces, donde quiera que quiera enlazar a su pdf, ponga

 Click me 

La primera línea le dice a Django que busque en los directorios configurados para archivos estáticos en settings.py . La ruta que utiliza en la etiqueta de anclaje es relativa a cualquiera de los directorios que configuró como directorios estáticos en settings.py . Cuando haga clic en el enlace renderizado, debería mostrar el PDF en su navegador, siempre que tenga los archivos estáticos correctamente rastreados.