mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| ===========================
 | |
| 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: http://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``:
 | |
| 
 | |
| .. code-block:: 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.python.org/pypi/reportlab
 | |
| .. _user guide: http://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.
 |