summaryrefslogtreecommitdiff
path: root/docs/howto
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2018-05-15 18:12:11 +0200
committerGitHub <noreply@github.com>2018-05-15 18:12:11 +0200
commita177f854c34718e473bcd0a2dc6c4fd935c8e327 (patch)
treed15e436c26edfd2037972c48095b4bcd2ad48505 /docs/howto
parent2dcc5d629a6439b5547cdd6e67815cabf608fcd4 (diff)
Fixed #16470 -- Allowed FileResponse to auto-set some Content headers.
Thanks Simon Charette, Jon Dufresne, and Tim Graham for the reviews.
Diffstat (limited to 'docs/howto')
-rw-r--r--docs/howto/outputting-pdf.txt94
1 files changed, 28 insertions, 66 deletions
diff --git a/docs/howto/outputting-pdf.txt b/docs/howto/outputting-pdf.txt
index fa911df169..9950c4316c 100644
--- a/docs/howto/outputting-pdf.txt
+++ b/docs/howto/outputting-pdf.txt
@@ -41,21 +41,21 @@ Write your view
===============
The key to generating PDFs dynamically with Django is that the ReportLab API
-acts on file-like objects, and Django's :class:`~django.http.HttpResponse`
-objects are file-like objects.
+acts on file-like objects, and Django's :class:`~django.http.FileResponse`
+objects accept file-like objects.
Here's a "Hello World" example::
- from django.http import HttpResponse
+ import io
+ from django.http import FileResponse
from reportlab.pdfgen import canvas
def some_view(request):
- # Create the HttpResponse object with the appropriate PDF headers.
- response = HttpResponse(content_type='application/pdf')
- response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
+ # Create a file-like buffer to receive PDF data.
+ buffer = io.BytesIO()
- # Create the PDF object, using the response object as its "file."
- p = canvas.Canvas(response)
+ # Create the PDF object, using the buffer as its "file."
+ p = canvas.Canvas(buffer)
# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
@@ -64,37 +64,35 @@ Here's a "Hello World" example::
# Close the PDF object cleanly, and we're done.
p.showPage()
p.save()
- return response
+
+ # FileResponse sets the Content-Disposition header so that browsers
+ # present the option to save the file.
+ return FileResponse(buffer, as_attachment=True, filename='hello.pdf')
The code and comments should be self-explanatory, but a few things deserve a
mention:
-* The response gets a special MIME type, :mimetype:`application/pdf`. This
- tells browsers that the document is a PDF file, rather than an HTML file.
- If you leave this off, browsers will probably interpret the output as
- HTML, which would result in ugly, scary gobbledygook in the browser
- window.
-
-* The response gets an additional ``Content-Disposition`` header, which
- contains the name of the PDF file. This filename is arbitrary: Call it
- whatever you want. It'll be used by browsers in the "Save as..." dialog, etc.
+* The response will automatically set the MIME type :mimetype:`application/pdf`
+ based on the filename extension. This tells browsers that the document is a
+ PDF file, rather than an HTML file or a generic `application/octet-stream`
+ binary content.
-* The ``Content-Disposition`` header starts with ``'attachment; '`` in this
- example. This forces Web browsers to pop-up a dialog box
- prompting/confirming how to handle the document even if a default is set
- on the machine. If you leave off ``'attachment;'``, browsers will handle
- the PDF using whatever program/plugin they've been configured to use for
- PDFs. Here's what that code would look like::
+* When ``as_attachment=True`` is passed to ``FileResponse``, it sets the
+ appropriate ``Content-Disposition`` header and that tells Web browsers to
+ pop-up a dialog box prompting/confirming how to handle the document even if a
+ default is set on the machine. If the ``as_attachment`` parameter is omitted,
+ browsers will handle the PDF using whatever program/plugin they've been
+ configured to use for PDFs.
- response['Content-Disposition'] = 'filename="somefilename.pdf"'
+* You can provide an arbitrary ``filename`` parameter. It'll be used by browsers
+ in the "Save as..." dialog.
-* Hooking into the ReportLab API is easy: Just pass ``response`` as the
- first argument to ``canvas.Canvas``. The ``Canvas`` class expects a
- file-like object, and :class:`~django.http.HttpResponse` objects fit the
- bill.
+* Hooking into the ReportLab API is easy: The same buffer passed as the first
+ argument to ``canvas.Canvas`` can be fed to the
+ :class:`~django.http.FileResponse` class.
* Note that all subsequent PDF-generation methods are called on the PDF
- object (in this case, ``p``) -- not on ``response``.
+ object (in this case, ``p``) -- not on ``buffer``.
* Finally, it's important to call ``showPage()`` and ``save()`` on the PDF
file.
@@ -105,42 +103,6 @@ mention:
with building PDF-generating Django views that are accessed by many people
at the same time.
-Complex PDFs
-============
-
-If you're creating a complex PDF document with ReportLab, consider using the
-:mod:`io` library as a temporary holding place for your PDF file. This
-library provides a file-like object interface that is particularly efficient.
-Here's the above "Hello World" example rewritten to use :mod:`io`::
-
- from io import BytesIO
- from reportlab.pdfgen import canvas
- from django.http import HttpResponse
-
- def some_view(request):
- # Create the HttpResponse object with the appropriate PDF headers.
- response = HttpResponse(content_type='application/pdf')
- response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
-
- buffer = BytesIO()
-
- # Create the PDF object, using the BytesIO object as its "file."
- p = canvas.Canvas(buffer)
-
- # Draw things on the PDF. Here's where the PDF generation happens.
- # See the ReportLab documentation for the full list of functionality.
- p.drawString(100, 100, "Hello world.")
-
- # Close the PDF object cleanly.
- p.showPage()
- p.save()
-
- # Get the value of the BytesIO buffer and write it to the response.
- pdf = buffer.getvalue()
- buffer.close()
- response.write(pdf)
- return response
-
Other formats
=============