web-dev-qa-db-fra.com

Comment montrer un PDF déposer dans une vue Django?

Est-il possible d'afficher un fichier PDF dans la vue Django, plutôt que de demander à l'utilisateur de le télécharger pour le voir?

Et si c'était possible, comment cela serait-il fait?

C'est ce que j'ai jusqu'à présent - 

@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
25
SImon

De manière simpliste, si vous avez un fichier PDF et que vous voulez le sortir via une vue Django, il vous suffit de vider le contenu du fichier dans la réponse et de l'envoyer avec le type MIME approprié.

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

Vous pouvez probablement simplement renvoyer la réponse directement sans spécifier Content-Disposition, mais cela indique mieux votre intention et vous permet également de spécifier le nom du fichier au cas où l'utilisateur déciderait de l'enregistrer.

Notez également que la vue ci-dessus ne gère pas le scénario dans lequel le fichier ne peut pas être ouvert ou lu pour une raison quelconque. Etant donné que cela est fait avec with, cela ne soulève aucune exception, mais vous devez quand même renvoyer une sorte de réponse. Vous pouvez simplement élever un Http404 ou autre chose.

29
Chris Pratt

Django a une classe spécialement conçue pour renvoyer des fichiers, FileResponse . Il diffuse les fichiers afin que vous n'ayez pas à lire le fichier en entier avant de le renvoyer. Voici:

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 vous avez des fichiers très volumineux ou si vous le faites souvent, une meilleure option serait probablement de les servir en dehors de Django en utilisant une configuration de serveur normale.

20
Flimm

Si vous travaillez sur une machine Windows, le fichier PDF doit être ouvert sous la forme rb et non 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
8
MKM

Sortez en ligne; si vous voulez que votre fichier soit lu depuis le serveur. Et aussi, la HttpResponse kwarg mimetype a été remplacée par 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
5
gajanan hegde

Suite à la réponse de @ radtek ci-dessus, j'ai décidé d'étudier un affichage de vue basé sur les classes. J'ai essayé d'utiliser View mais il n'y avait pas de méthode get_context_data().

J'ai cherché ici pour des conseils. Je me suis installé pour BaseDetailView car je ne voulais afficher qu'un seul objet.

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

Commentaire

1 Cette ligne accède à un argument nommé pk transmis par l'URL appelant la vue.

2 Cette ligne récupère l'objet de modèle pdf réel.

3 J'ai défini une méthode filename(self): return os.path.basename(self.file.name) dans mon modèle pour m'aider à obtenir uniquement le nom de fichier plus l'extension.

4 Cette ligne obtient le chemin complet du fichier.

Ensuite, utilisez la réponse de fichier comme expliqué dans les réponses ci-dessus. Pensez également à utiliser rb pour lire le fichier pdf.

3
chidimo

Voici un cas d'utilisation typique pour afficher un PDF à l'aide de vues basées sur des classes:

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

Pour générer votre propre fichier PDF avec reportlab, consultez la documentation du projet Django sur PDF Generation .

La réponse de Chris Pratt montre un bon exemple d'ouverture de fichiers PDF existants.

2
radtek

Les navigateurs ne sont pas PDF lecteurs (à moins qu'ils aient le plug-in/addon approprié).

Vous voudrez peut-être rendre le PDF au format HTML à la place, ce qui peut être fait à partir du serveur ou du serveur .

0
Gonzalo

ça a fonctionné pour moi

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
German Lopez