outputting-pdf.txt 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. ===========================
  2. Outputting PDFs with Django
  3. ===========================
  4. This document explains how to output PDF files dynamically using Django views.
  5. This is made possible by the excellent, open-source ReportLab_ Python PDF
  6. library.
  7. The advantage of generating PDF files dynamically is that you can create
  8. customized PDFs for different purposes -- say, for different users or different
  9. pieces of content.
  10. For example, Django was used at kusports.com_ to generate customized,
  11. printer-friendly NCAA tournament brackets, as PDF files, for people
  12. participating in a March Madness contest.
  13. .. _ReportLab: https://www.reportlab.com/opensource/
  14. .. _kusports.com: http://www.kusports.com/
  15. Install ReportLab
  16. =================
  17. The ReportLab library is `available on PyPI`_. A `user guide`_ (not
  18. coincidentally, a PDF file) is also available for download.
  19. You can install ReportLab with ``pip``:
  20. .. console::
  21. $ pip install reportlab
  22. Test your installation by importing it in the Python interactive interpreter::
  23. >>> import reportlab
  24. If that command doesn't raise any errors, the installation worked.
  25. .. _available on PyPI: https://pypi.org/project/reportlab/
  26. .. _user guide: https://www.reportlab.com/docs/reportlab-userguide.pdf
  27. Write your view
  28. ===============
  29. The key to generating PDFs dynamically with Django is that the ReportLab API
  30. acts on file-like objects, and Django's :class:`~django.http.HttpResponse`
  31. objects are file-like objects.
  32. Here's a "Hello World" example::
  33. from reportlab.pdfgen import canvas
  34. from django.http import HttpResponse
  35. def some_view(request):
  36. # Create the HttpResponse object with the appropriate PDF headers.
  37. response = HttpResponse(content_type='application/pdf')
  38. response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
  39. # Create the PDF object, using the response object as its "file."
  40. p = canvas.Canvas(response)
  41. # Draw things on the PDF. Here's where the PDF generation happens.
  42. # See the ReportLab documentation for the full list of functionality.
  43. p.drawString(100, 100, "Hello world.")
  44. # Close the PDF object cleanly, and we're done.
  45. p.showPage()
  46. p.save()
  47. return response
  48. The code and comments should be self-explanatory, but a few things deserve a
  49. mention:
  50. * The response gets a special MIME type, :mimetype:`application/pdf`. This
  51. tells browsers that the document is a PDF file, rather than an HTML file.
  52. If you leave this off, browsers will probably interpret the output as
  53. HTML, which would result in ugly, scary gobbledygook in the browser
  54. window.
  55. * The response gets an additional ``Content-Disposition`` header, which
  56. contains the name of the PDF file. This filename is arbitrary: Call it
  57. whatever you want. It'll be used by browsers in the "Save as..." dialog, etc.
  58. * The ``Content-Disposition`` header starts with ``'attachment; '`` in this
  59. example. This forces Web browsers to pop-up a dialog box
  60. prompting/confirming how to handle the document even if a default is set
  61. on the machine. If you leave off ``'attachment;'``, browsers will handle
  62. the PDF using whatever program/plugin they've been configured to use for
  63. PDFs. Here's what that code would look like::
  64. response['Content-Disposition'] = 'filename="somefilename.pdf"'
  65. * Hooking into the ReportLab API is easy: Just pass ``response`` as the
  66. first argument to ``canvas.Canvas``. The ``Canvas`` class expects a
  67. file-like object, and :class:`~django.http.HttpResponse` objects fit the
  68. bill.
  69. * Note that all subsequent PDF-generation methods are called on the PDF
  70. object (in this case, ``p``) -- not on ``response``.
  71. * Finally, it's important to call ``showPage()`` and ``save()`` on the PDF
  72. file.
  73. .. note::
  74. ReportLab is not thread-safe. Some of our users have reported odd issues
  75. with building PDF-generating Django views that are accessed by many people
  76. at the same time.
  77. Complex PDFs
  78. ============
  79. If you're creating a complex PDF document with ReportLab, consider using the
  80. :mod:`io` library as a temporary holding place for your PDF file. This
  81. library provides a file-like object interface that is particularly efficient.
  82. Here's the above "Hello World" example rewritten to use :mod:`io`::
  83. from io import BytesIO
  84. from reportlab.pdfgen import canvas
  85. from django.http import HttpResponse
  86. def some_view(request):
  87. # Create the HttpResponse object with the appropriate PDF headers.
  88. response = HttpResponse(content_type='application/pdf')
  89. response['Content-Disposition'] = 'attachment; filename="somefilename.pdf"'
  90. buffer = BytesIO()
  91. # Create the PDF object, using the BytesIO object as its "file."
  92. p = canvas.Canvas(buffer)
  93. # Draw things on the PDF. Here's where the PDF generation happens.
  94. # See the ReportLab documentation for the full list of functionality.
  95. p.drawString(100, 100, "Hello world.")
  96. # Close the PDF object cleanly.
  97. p.showPage()
  98. p.save()
  99. # Get the value of the BytesIO buffer and write it to the response.
  100. pdf = buffer.getvalue()
  101. buffer.close()
  102. response.write(pdf)
  103. return response
  104. Other formats
  105. =============
  106. Notice that there isn't a lot in these examples that's PDF-specific -- just the
  107. bits using ``reportlab``. You can use a similar technique to generate any
  108. arbitrary format that you can find a Python library for. Also see
  109. :doc:`/howto/outputting-csv` for another example and some techniques you can use
  110. when generated text-based formats.
  111. .. seealso::
  112. Django Packages provides a `comparison of packages
  113. <https://djangopackages.org/grids/g/pdf/>`_ that help generate PDF files
  114. from Django.