Dieses Dokument erklärt, wie man mithilfe von Django-Views dynamisch PDF-Dateien erzeugen kann. Dies wird durch die ausgezeichnete open-source ReportLab-Bibliothek ermöglicht.
Wenn du PDF-Dateien dynamisch erstellst, hast du die Möglichkeit, diese für bestimmte Zwecke, wie für unterschiedliche Benutzer oder für unterschiedliche Inhalte etc., entsprechend anzupassen.
So wurde Django zum Beispiel auf kusports.com genutzt, um angepasste druckfreundliche NCAA-Turnierpläne zu erzeugen.
Lade die ReportLab-Bibliothek von http://www.reportlab.org/downloads.html herunter und installiere sie entsprechend der Anleitung im Benutzerhandbuch.
Teste deine Installation, indem du die Bibliothek in Pythons interaktiven Interpreter importierst:
>>> import reportlab
Wenn dieser Befehl keine Fehler wirft, war die Installation erfolgreich.
Der Schlüssel zur Erstellung von PDFs mit Django ist, dass die ReportLab-API auf dateiähnlichen Objekten operiert und dass Instanzen von Djangos HttpResponse-Klasse solchen dateiähnlichen Objekten entsprechen.
Hier ein kleines "Hallo, Welt"-Beispiel:
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Erzeuge das HttpResponse-Objekt mit dem entsprechenden PDF-Header.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'
# Erzeuge das PDF-Objekt und verwende das Response-Objekt als Datei.
p = canvas.Canvas(response)
# Zeichne etwas im PDF. Hier geschieht nun die eigentliche
# Generierung des PDFs. Eine vollstaendige Liste aller Funkionen
# findest du in der ReportLab-Dokumentation.
p.drawString(100, 100, "Hello world.")
# Sobald du nun das PDF-Objekt schliesst, ist alles erledigt.
p.showPage()
p.save()
return response
Der Code und auch die Kommentare sollten bereits alles erklären, aber ein paar Dinge sollten dennoch explizit erwähnt werden:
Die Server-Antwort hat mit application/pdf einen speziellen MIME-Type, wodurch der Browser erfährt, dass es sich bei der enthaltenen Datei um ein PDF und nicht um eine HTML-Datei handelt. Wenn du diesen MIME-Type nicht explizit setzt, wird der Browser die Daten wahrscheinlich versuchen, wie HTML zu behandeln, was (um es freundlich auszudrücken) nicht sonderlich gut funktioniert.
Die Antwort enthält zusätzlich noch den Content-Disposition-Header, welcher den Namen des PDFs enthält. Der Dateiname ist beliebig wählbar und wird u.a. vom "Speichern unter..."-Dialog im Browser verwendet.
Der Content-Disposition-Header fängt hierfür mit 'attachment; ' an. Das erzwingt im Browser einen Popup-Dialog, um festzulegen, was nun weiter mit der Datei geschehen soll (selbst wenn bereits eine Standardaktion auf diesem Rechner festgelegt ist). Wenn du 'attachment; ' weglässt, wird der Browser die Datei mit dem jeweilig festgelegten Programm oder Plugin verarbeiten. So sollte der Code hierfür aussehen:
response['Content-Disposition'] = 'filename=somefilename.pdf'
Die ReportLab-API hier zu verwenden, ist einfach: Übergib der canvas.Canvas-Methode einfach das response-Objekt. Canvas erwartet ein dateiähnliches Objekt und HttpResponse ist eben ein solches.
Alle weiteren Methoden zur PDF-Generierung werden direkt auf dem PDF-Objekt ausgeführt (hier p) und nicht auf response.
Zu guter Letzt ist es noch wichtig, dass du showPage() und save() für die PDF-Datei aufrufst.
Wenn du komplexere PDF-Dokumente mit ReportLab erzeugst, könnte dir auch die cStringIO-Bibliothek von Nutzen sein, um als Zwischenspeicher für die PDF-Datei zu dienen. Die cStringIO-Bibliothek bietet eine dateiähnliche Schnittstelle für Strings. So würde das obere Beispiel nun mit cStringIO aussehen:
from cStringIO import StringIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse
def some_view(request):
# Erzeuge das HttpResponse-Objekt mit den entsprechenden PDF-Headern.
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'
buffer = StringIO()
# Erzeuge das PDF-Objekt und verwende ein cStringIO-Objekt als
# "Datei".
p = canvas.Canvas(buffer)
# Zeichne etwas im PDF. Hier geschieht nun die eigentliche
# Generierung des PDFs. Eine vollstaendige Liste aller Funkionen
# findest du in der ReportLab-Dokumentation.
p.drawString(100, 100, "Hello world.")
# Schließe das PDF-Objekt.
p.showPage()
p.save()
# Frage den Buffer aus dem StringIO-Objekt ab und schreibe ihn in die
# Antwort.
pdf = buffer.getvalue()
buffer.close()
response.write(pdf)
return response
Dir ist sicher aufgefallen, dass nicht viel in diesen Beispielen wirklich PDF-spezifisch ist (mit Ausnahme der Stellen, wo reportlab verwendet wird). Mit den hier beschriebenen oder ähnlichen Techniken kannst du beliebige Dateien erstellen, für deren Format du eine Python-Bibliothek findest. Schau dir auch CSV-Daten mit Django ausgeben für ein weiteres Beispiel für ein textbasiertes Dateiformat an.
Mar 01, 2010