Create PDFs from Django templates
Tags: django, python
Published: 2023-01-21 13:48:55

---
title: Create PDFs from Django templates
published: true
date: 2023-01-21 13:47:56 UTC
tags: Django,Python
canonical_url: https://www.rockandnull.com/django-pdf-generator/
---

 ![Create PDFs from Django templates](https://images.unsplash.com/photo-1468779036391-52341f60b55d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGRvY3VtZW50fGVufDB8fHx8MTY3NDMwODI5OQ&ixlib=rb-4.0.3&q=80&w=2000)

Creating PDFs has been an easy task in Python due to the plenty of high-quality libraries that exist out there.

If you have tried doing it, you would be pleasantly surprised by how quickly you can create a PDF using one of those libraries. On the other hand, you would notice that most of them require drawing the elements "manually" on the page. That is defining the exact position of each element using coordinates. Even the [official Django how-to](https://docs.djangoproject.com/en/dev/howto/outputting-pdf/)section for creating PDFs mentions a way of creating PDFs using the coordinates of the consisting elements.

Yet, as web and Django developers, we are placing elements on a "page" without coordinates. We are using HTML and CSS for placing and styling components all the time. Wouldn't be great if we could create a PDF similar to how we create pages in Django? Just export the result of a template rendering into a PDF.

This is exactly what we will do in this post.

## Set up

Firstly, install `xhtml2pdf` that provides the HTML -> PDF functionality:

```
pip install xhtml2pdf
```

## Sample code

In the following short snippet, we show how we could create an invoice PDF from a Django template. We assume that the `invoice.html` template contains the layout for displaying the necessary info for an invoice, including an image logo. All the data are stored in an `Invoice` model.

```
class InvoiceView(View):
    @staticmethod
    def get(request, invoice_id):
        invoice = get_object_or_404(Invoice, id=invoice_id) # 1.
        return _render_to_pdf(invoice)

def _render_to_pdf(invoice):
    template = get_template("invoice.html")
    html = template.render(
        {
            "logos": os.path.join(STATIC_ROOT, "logo.png"), # 2.
            "invoice": invoice,
        }
    )
    
    pdf = BytesIO()
    pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), pdf) # 3.
    
    res = HttpResponse(pdf.getvalue(), content_type="application/pdf")
    res["Content-Disposition"] = \
        f"attachment; filename=invoice{invoice.id}.pdf" # 4.
    
    return response
```

1. Fetch the model like you would normally do when needing some data from the DB to render a template.
2. Pass to the template any context data as you would do normally. The special case here is the images that need to have an absolute path instead of a relative path. Use the `os.path.join()` method to create the absolute filesystem path of the images in your static files. For a reminder on how to set up the static files, consult the [official documentation](https://docs.djangoproject.com/en/dev/howto/static-files/).
3. Use the [`xhtml2pdf`](https://pypi.org/project/xhtml2pdf/) to render the PDF from your template, and convert it to binary data to be downloaded in the next step.
4. This is how to declare the `HttpResponse`so the browser will understand that this is a binary (PDF) file that cannot be displayed in the browser but needs to be downloaded.  

Hopefully, this was a quick and easy tutorial on how to create a PDF from your Django template.

Happy coding!