123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- ===========================
- Outputting PDFs with Django
- ===========================
- This document explains how to output PDF files dynamically using Django views.
- This is made possible by the excellent, open-source ReportLab_ Python PDF
- library.
- The advantage of generating PDF files dynamically is that you can create
- customized PDFs for different purposes -- say, for different users or different
- pieces of content.
- For example, Django was used at kusports.com_ to generate customized,
- printer-friendly NCAA tournament brackets, as PDF files, for people
- participating in a March Madness contest.
- .. _ReportLab: https://www.reportlab.com/opensource/
- .. _kusports.com: http://www.kusports.com/
- Install ReportLab
- =================
- The ReportLab library is `available on PyPI`_. A `user guide`_ (not
- coincidentally, a PDF file) is also available for download.
- You can install ReportLab with ``pip``:
- .. console::
- $ pip install reportlab
- Test your installation by importing it in the Python interactive interpreter::
- >>> import reportlab
- If that command doesn't raise any errors, the installation worked.
- .. _available on PyPI: https://pypi.org/project/reportlab/
- .. _user guide: https://www.reportlab.com/docs/reportlab-userguide.pdf
- 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.
- Here's a "Hello World" example::
- 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"'
- # Create the PDF object, using the response object as its "file."
- p = canvas.Canvas(response)
- # 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, and we're done.
- p.showPage()
- p.save()
- return response
- 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 ``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::
- response['Content-Disposition'] = 'filename="somefilename.pdf"'
- * 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.
- * Note that all subsequent PDF-generation methods are called on the PDF
- object (in this case, ``p``) -- not on ``response``.
- * Finally, it's important to call ``showPage()`` and ``save()`` on the PDF
- file.
- .. note::
- ReportLab is not thread-safe. Some of our users have reported odd issues
- 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
- =============
- Notice that there isn't a lot in these examples that's PDF-specific -- just the
- bits using ``reportlab``. You can use a similar technique to generate any
- arbitrary format that you can find a Python library for. Also see
- :doc:`/howto/outputting-csv` for another example and some techniques you can use
- when generated text-based formats.
- .. seealso::
- Django Packages provides a `comparison of packages
- <https://djangopackages.org/grids/g/pdf/>`_ that help generate PDF files
- from Django.
|