<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David López</title>
    <description>The latest articles on DEV Community by David López (@davilopez).</description>
    <link>https://dev.to/davilopez</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F165600%2Fe2d1b54c-4045-4123-b5e5-ab64d306e4fe.jpeg</url>
      <title>DEV Community: David López</title>
      <link>https://dev.to/davilopez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davilopez"/>
    <language>en</language>
    <item>
      <title>Django: Render HTML as PDF to the browser</title>
      <dc:creator>David López</dc:creator>
      <pubDate>Sun, 29 Sep 2019 20:01:08 +0000</pubDate>
      <link>https://dev.to/davilopez/django-render-html-as-pdf-to-the-browser-1i27</link>
      <guid>https://dev.to/davilopez/django-render-html-as-pdf-to-the-browser-1i27</guid>
      <description>&lt;p&gt;The main part of every business application or CRM is to print out some documents like reports, invoices, etc and PDF is the most popular format. As this being something that usual, it is also surprising how complicated can be sometimes to perform such a task.&lt;/p&gt;

&lt;p&gt;I have been involved in a small Django project, where definitely printing PDF documents was required as basic functionality. After a little of search, I found a Python adaption of an already known library from my days in PHP world,&lt;a href="http://www.fpdf.org/"&gt;FPDF&lt;/a&gt; , and in this case, &lt;a href="https://github.com/reingart/pyfpdf"&gt;PyFDPF&lt;/a&gt; is the one that I used.&lt;/p&gt;

&lt;p&gt;But let us don't miss more time and get our hands dirty so to produce a PDF file in Django and display it in the browser.&lt;/p&gt;

&lt;p&gt;First let's install the library, this can we done using pip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;fpdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;but it will be better including it the requirements.txt, as recommended by the &lt;em&gt;Best Practices for Dependency Management&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;fpdf&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;1.7.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We will create a template file, which it will contain the HTML to be rendered in the pdf. I like to place these files in a specific folder and therefore keep my templates organized.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
└── main
|    └── ...
|    └── urls.py
└── my_app
     └── ...
     └── pdfs
     └── templates
          └── __init__.py
          └── pdf
               └── example.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Below you can find an example of HTML code that I picked up from the document of the library and to test the elements. Including the Django built-in &lt;em&gt;static&lt;/em&gt; template tag allows us to include pictures from your static folder in the HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;{% load static %}

&lt;span class="nt"&gt;&amp;lt;H1&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Example&lt;span class="nt"&gt;&amp;lt;/H1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Basic usage&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;You can now easily print text mixing different
    styles : &lt;span class="nt"&gt;&amp;lt;B&amp;gt;&lt;/span&gt;bold&lt;span class="nt"&gt;&amp;lt;/B&amp;gt;&lt;/span&gt;, &lt;span class="nt"&gt;&amp;lt;I&amp;gt;&lt;/span&gt;italic&lt;span class="nt"&gt;&amp;lt;/I&amp;gt;&lt;/span&gt;, &lt;span class="nt"&gt;&amp;lt;U&amp;gt;&lt;/span&gt;underlined&lt;span class="nt"&gt;&amp;lt;/U&amp;gt;&lt;/span&gt;, or
    &lt;span class="nt"&gt;&amp;lt;B&amp;gt;&amp;lt;I&amp;gt;&amp;lt;U&amp;gt;&lt;/span&gt;all at once&lt;span class="nt"&gt;&amp;lt;/U&amp;gt;&amp;lt;/I&amp;gt;&amp;lt;/B&amp;gt;&lt;/span&gt;!&lt;span class="nt"&gt;&amp;lt;BR&amp;gt;&lt;/span&gt;You can also insert links
    on text, such as &lt;span class="nt"&gt;&amp;lt;A&lt;/span&gt; &lt;span class="na"&gt;HREF=&lt;/span&gt;&lt;span class="s"&gt;"http://www.fpdf.org"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;www.fpdf.org&lt;span class="nt"&gt;&amp;lt;/A&amp;gt;&lt;/span&gt;,
    or on an image: click on the logo.&lt;span class="nt"&gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Sample List&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;option 1&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ol&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;option 2&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;option 3&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"50%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"30%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Header 1&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"70%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;header 2&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;cell 1&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;cell 2&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;cell 2&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;cell 3&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So we are ready to create the method to render that HTML in a PDF document and deliverit to the browser for visualization, wrapping it into an HTTPResponse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.shortcuts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.template.loader&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_to_string&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fpdf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FPDF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTMLMixin&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HtmlPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FPDF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTMLMixin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;    
    &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HtmlPdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;render_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pdf/example.html'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'S'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'latin-1'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'application/pdf'&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Creating a class with the objects FPDF and HTMLMixin will make the trick so that the &lt;em&gt;write_html&lt;/em&gt; method can be used within the FPDF logic. This method requires a string containing the HTML code, therefore, we use Django's &lt;em&gt;render_to_string&lt;/em&gt; to convert into a string the Template object open by the &lt;em&gt;loader&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;As the documentation states, when using Python 3.x you need to add&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;.encode('latin-1')&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 to the method output in order to render correctly.&lt;/p&gt;

&lt;p&gt;We are just missing a way to call &lt;em&gt;print_pdf&lt;/em&gt; and we can do that through a new entry in the urls.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;myapp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;web_views&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"pdf/example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;web_views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_pdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"print_pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Well if you have arrived this far and have a running Django instance, for example using Django's functionality to run a server, you will be able to access the pdf calling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;http://127.0.0.1:8000/pdf/example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As said before this is a basic example that can used to render a HTML into a PDF and display it in the browser, however, it is possible to save the file locally, just changing the pdf.output syntaxis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'my_app'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'pdfs'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;'/example.pdf'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'F'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Notes:
&lt;/h2&gt;

&lt;p&gt;You still have a long journey to create a full pdf file that can be presented as a report from your application, for that reason I would suggest you to dive into the documentation of &lt;a href="https://github.com/reingart/pyfpdf"&gt;PyFDPF&lt;/a&gt; to discover more functionality.&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>pdf</category>
    </item>
  </channel>
</rss>
