{"title":"Outputting PDFs with Django","version":"1.10","locale":"en","docname":"howto/outputting-pdf","url":"/en/1.10/howto/outputting-pdf/","canonical":"https://djangodocs.dev/en/1.10/howto/outputting-pdf/","summary":"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…","html":"<h1>Outputting PDFs with Django<a class=\"heading-anchor\" href=\"#outputting-pdfs-with-django\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>This document explains how to output PDF files dynamically using Django views.\nThis is made possible by the excellent, open-source <a class=\"reference external\" href=\"http://www.reportlab.com/opensource/\">ReportLab</a> Python PDF\nlibrary.</p>\n<p>The advantage of generating PDF files dynamically is that you can create\ncustomized PDFs for different purposes – say, for different users or different\npieces of content.</p>\n<p>For example, Django was used at <a class=\"reference external\" href=\"http://www.kusports.com/\">kusports.com</a> to generate customized,\nprinter-friendly NCAA tournament brackets, as PDF files, for people\nparticipating in a March Madness contest.</p>\n<section id=\"install-reportlab\">\n<h2>Install ReportLab<a class=\"heading-anchor\" href=\"#install-reportlab\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The ReportLab library is <a class=\"reference external\" href=\"https://pypi.python.org/pypi/reportlab\">available on PyPI</a>. A <a class=\"reference external\" href=\"http://www.reportlab.com/docs/reportlab-userguide.pdf\">user guide</a> (not\ncoincidentally, a PDF file) is also available for download.\nYou can install ReportLab with <code class=\"docutils literal notranslate\"><span class=\"pre\">pip</span></code>:</p>\n<div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code><span class=\"gp\">$ </span>pip<span class=\"w\"> </span>install<span class=\"w\"> </span>reportlab\n</code></pre></div>\n<p>Test your installation by importing it in the Python interactive interpreter:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">reportlab</span>\n</code></pre></div>\n<p>If that command doesn’t raise any errors, the installation worked.</p>\n</section>\n<section id=\"write-your-view\">\n<h2>Write your view<a class=\"heading-anchor\" href=\"#write-your-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>The key to generating PDFs dynamically with Django is that the ReportLab API\nacts on file-like objects, and Django’s <a class=\"reference internal\" href=\"/en/1.10/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a>\nobjects are file-like objects.</p>\n<p>Here’s a “Hello World” example:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">reportlab.pdfgen</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">canvas</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponse</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">some_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Create the HttpResponse object with the appropriate PDF headers.</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span><span class=\"n\">content_type</span><span class=\"o\">=</span><span class=\"s1\">&#39;application/pdf&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;Content-Disposition&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;attachment; filename=&quot;somefilename.pdf&quot;&#39;</span>\n\n    <span class=\"c1\"># Create the PDF object, using the response object as its &quot;file.&quot;</span>\n    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">canvas</span><span class=\"o\">.</span><span class=\"n\">Canvas</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Draw things on the PDF. Here&#39;s where the PDF generation happens.</span>\n    <span class=\"c1\"># See the ReportLab documentation for the full list of functionality.</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">drawString</span><span class=\"p\">(</span><span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Hello world.&quot;</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Close the PDF object cleanly, and we&#39;re done.</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">showPage</span><span class=\"p\">()</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"n\">response</span>\n</code></pre></div>\n<p>The code and comments should be self-explanatory, but a few things deserve a\nmention:</p>\n<ul>\n<li><p>The response gets a special MIME type, <em class=\"mimetype\">application/pdf</em>. This\ntells browsers that the document is a PDF file, rather than an HTML file.\nIf you leave this off, browsers will probably interpret the output as\nHTML, which would result in ugly, scary gobbledygook in the browser\nwindow.</p></li>\n<li><p>The response gets an additional <code class=\"docutils literal notranslate\"><span class=\"pre\">Content-Disposition</span></code> header, which\ncontains the name of the PDF file. This filename is arbitrary: Call it\nwhatever you want. It’ll be used by browsers in the “Save as…” dialog, etc.</p></li>\n<li><p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">Content-Disposition</span></code> header starts with <code class=\"docutils literal notranslate\"><span class=\"pre\">'attachment;</span> <span class=\"pre\">'</span></code> in this\nexample. This forces Web browsers to pop-up a dialog box\nprompting/confirming how to handle the document even if a default is set\non the machine. If you leave off <code class=\"docutils literal notranslate\"><span class=\"pre\">'attachment;'</span></code>, browsers will handle\nthe PDF using whatever program/plugin they’ve been configured to use for\nPDFs. Here’s what that code would look like:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;Content-Disposition&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;filename=&quot;somefilename.pdf&quot;&#39;</span>\n</code></pre></div>\n</li>\n<li><p>Hooking into the ReportLab API is easy: Just pass <code class=\"docutils literal notranslate\"><span class=\"pre\">response</span></code> as the\nfirst argument to <code class=\"docutils literal notranslate\"><span class=\"pre\">canvas.Canvas</span></code>. The <code class=\"docutils literal notranslate\"><span class=\"pre\">Canvas</span></code> class expects a\nfile-like object, and <a class=\"reference internal\" href=\"/en/1.10/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> objects fit the\nbill.</p></li>\n<li><p>Note that all subsequent PDF-generation methods are called on the PDF\nobject (in this case, <code class=\"docutils literal notranslate\"><span class=\"pre\">p</span></code>) – not on <code class=\"docutils literal notranslate\"><span class=\"pre\">response</span></code>.</p></li>\n<li><p>Finally, it’s important to call <code class=\"docutils literal notranslate\"><span class=\"pre\">showPage()</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">save()</span></code> on the PDF\nfile.</p></li>\n</ul>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>ReportLab is not thread-safe. Some of our users have reported odd issues\nwith building PDF-generating Django views that are accessed by many people\nat the same time.</p>\n</aside>\n</section>\n<section id=\"complex-pdfs\">\n<h2>Complex PDFs<a class=\"heading-anchor\" href=\"#complex-pdfs\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>If you’re creating a complex PDF document with ReportLab, consider using the\n<a class=\"reference external\" href=\"https://docs.python.org/3/library/io.html#module-io\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">io</span></code></a> library as a temporary holding place for your PDF file. This\nlibrary provides a file-like object interface that is particularly efficient.\nHere’s the above “Hello World” example rewritten to use <a class=\"reference external\" href=\"https://docs.python.org/3/library/io.html#module-io\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">io</span></code></a>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">io</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">BytesIO</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">reportlab.pdfgen</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">canvas</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">HttpResponse</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">some_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"c1\"># Create the HttpResponse object with the appropriate PDF headers.</span>\n    <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span><span class=\"n\">content_type</span><span class=\"o\">=</span><span class=\"s1\">&#39;application/pdf&#39;</span><span class=\"p\">)</span>\n    <span class=\"n\">response</span><span class=\"p\">[</span><span class=\"s1\">&#39;Content-Disposition&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;attachment; filename=&quot;somefilename.pdf&quot;&#39;</span>\n\n    <span class=\"n\">buffer</span> <span class=\"o\">=</span> <span class=\"n\">BytesIO</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># Create the PDF object, using the BytesIO object as its &quot;file.&quot;</span>\n    <span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">canvas</span><span class=\"o\">.</span><span class=\"n\">Canvas</span><span class=\"p\">(</span><span class=\"n\">buffer</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Draw things on the PDF. Here&#39;s where the PDF generation happens.</span>\n    <span class=\"c1\"># See the ReportLab documentation for the full list of functionality.</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">drawString</span><span class=\"p\">(</span><span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Hello world.&quot;</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># Close the PDF object cleanly.</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">showPage</span><span class=\"p\">()</span>\n    <span class=\"n\">p</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n\n    <span class=\"c1\"># Get the value of the BytesIO buffer and write it to the response.</span>\n    <span class=\"n\">pdf</span> <span class=\"o\">=</span> <span class=\"n\">buffer</span><span class=\"o\">.</span><span class=\"n\">getvalue</span><span class=\"p\">()</span>\n    <span class=\"n\">buffer</span><span class=\"o\">.</span><span class=\"n\">close</span><span class=\"p\">()</span>\n    <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">write</span><span class=\"p\">(</span><span class=\"n\">pdf</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">response</span>\n</code></pre></div>\n</section>\n<section id=\"other-formats\">\n<h2>Other formats<a class=\"heading-anchor\" href=\"#other-formats\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Notice that there isn’t a lot in these examples that’s PDF-specific – just the\nbits using <code class=\"docutils literal notranslate\"><span class=\"pre\">reportlab</span></code>. You can use a similar technique to generate any\narbitrary format that you can find a Python library for. Also see\n<a class=\"reference internal\" href=\"/en/1.10/howto/outputting-csv/\"><span class=\"doc\">Outputting CSV with Django</span></a> for another example and some techniques you can use\nwhen generated text-based formats.</p>\n<aside class=\"admonition admonition-seealso\">\n<p class=\"admonition-title\">See also</p>\n<p>Django Packages provides a <a class=\"reference external\" href=\"https://djangopackages.org/grids/g/pdf/\">comparison of packages</a> that help generate PDF files\nfrom Django.</p>\n</aside>\n</section>","rootId":"outputting-pdfs-with-django","toc":[{"title":"Install ReportLab","anchor":"install-reportlab","children":[]},{"title":"Write your view","anchor":"write-your-view","children":[]},{"title":"Complex PDFs","anchor":"complex-pdfs","children":[]},{"title":"Other formats","anchor":"other-formats","children":[]}],"breadcrumbs":[{"docname":"howto/index","title":"“How-to” guides","url":"/en/1.10/howto/"}],"prev":{"docname":"howto/outputting-csv","title":"Outputting CSV with Django","url":"/en/1.10/howto/outputting-csv/"},"next":{"docname":"howto/static-files/index","title":"Managing static files (e.g. images, JavaScript, CSS)","url":"/en/1.10/howto/static-files/"},"formats":{"html":"/en/1.10/howto/outputting-pdf/","markdown":"/en/1.10/howto/outputting-pdf.md","json":"/en/1.10/howto/outputting-pdf.json"},"source":"https://github.com/django/django/blob/stable/1.10.x/docs/howto/outputting-pdf.txt","official":"https://docs.djangoproject.com/en/1.10/howto/outputting-pdf/","inVersions":["dev","6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9","1.8"],"inLocales":["en","fr","ja","id","pt-br","es","el","pl"]}