Django: how to create PDF, MS Word and Excel documents from templates

Posted on Mon 11 July 2016 in Programming

Django and PDF, MS Word, Excel templates

If you’re building a Django system that implies serving some kind of documents like reports or bills, chances are you want to provide docs in various formats from PDF to MS Word to HTML. But how to implement this without resorting to numerous templates and packages for each document type?

To tackle this issue I wrote templated_docs - a Django package that allows you to generate documents in multiple formats from just one template. And what’s even better is that you can use a regular Django templating language inside those docs!

In this post I’ll give you a gist of what you can do with this module.

Installation

1. Install LibreOffice

Templated-docs uses LibreOffice for conversion under the hood, so make sure you have a recent version installed (5.x versions will do fine). There is no need of having LibreOffice running all the time, in fact, you don’t even need a graphical subsystem to be installed on your server. We’ll use the suite as a library via the LibreOfficeKit API. Note the path Libreoffice has been installed to, we might need it later.

2. Install templated-docs

Installation is as simple as pip install templated-docs. Don’t forget to add templated_docs to your INSTALLED_APPS Django settings. Then specify the path to LibreOffice’s program directory in your settings:

TEMPLATED_DOCS_LIBREOFFICE_PATH = '/usr/share/libreoffice/program'

If you are using cpython you may need the libffi development package in order to compile CFFI.

  • Ubuntu: apt-get install libffi-dev
  • MacOS: brew install libffi

3. There is no step 3, we’re all set!

Usage example

Let’s put together a dead-simple system for issuing invoices. What we have here is a Customer model, and an InvoiceForm form to fill in some required fields.

# models.py
from django.db import models


class Customer(models.Model):
    name = models.CharField(max_length=200)
    address = models.TextField()

    def __str__(self):
        return self.name


# forms.py
from django import forms

from invoices.models import Customer


class InvoiceForm(forms.Form):
    FORMAT_CHOICES = (
        ('pdf', 'PDF'),
        ('docx', 'MS Word'),
        ('html', 'HTML'),
    )
    number = forms.CharField(label='Invoice #')
    customer = forms.ModelChoiceField(queryset=Customer.objects.all())
    subject = forms.CharField()
    amount = forms.DecimalField()
    format = forms.ChoiceField(choices=FORMAT_CHOICES)


# views.py
from django.shortcuts import render

from templated_docs import fill_template
from templated_docs.http import FileResponse

from invoices.forms import InvoiceForm


def invoice_view(request):
    form = InvoiceForm(request.POST or None)

    if form.is_valid():
        doctype = form.cleaned_data['format']
        filename = fill_template(
            'invoices/invoice.odt', form.cleaned_data,
            output_format=doctype)
        visible_filename = 'invoice.{}'.format(doctype)

        return FileResponse(filename, visible_filename)
    else:
        return render(request, 'invoices/form.html', {'form': form})

Next, create the actual invoice template and save it as invoices/invoice.odt in your Django templates’ folder. It could look like this:

An invoice sample

And that’s it! Fill out the form, choose the format you need, and instantly get a templated and converted document (the one in the picture is PDF):

An invoice sample

All the sample code, including the template, is available for playing in the example/ folder of the project’s repository.

Templated_docs offers more than a simple document generation. For example, you can embed images in documents and easily create Django management command that generate docs. Consult the documentation for more information.

Have you found an interesting applicaton for this package? Share in comments!

Read on:

What do you think about it? Share your thoughts!