Test Application

Lets setup our initial application. Create a new Django application, setup virtualenv and create a couple of models and register them in our Admin.

The only not ordinary aspect her is that we override the save method of the sales model to calculate the price. Lets make and migrate these.

python manage.py makemigrations

python manage.py migrate

Our app is in its basic form, lets create some users of our app, we need a superuser, and a 2 more users for this example (be sure to give the first and last names)

We will be building a sales report, so lets populate our database. We dont want to manually go through the admin panel and add these records, so lets build a simple seeder, a method we can run which will populate our database for us.

This class just creates a list of product titles when instantiated and then in the method seed it will run 20 times and create us 20 products and 20 sales, we use random to generate some random attributes for us.

We call this by running it from our terminal, we could build a management command to run this if needed, for a walkthrough of management commands see here.

Our database has been populated now, so lets build our report, the first thing we need is to bring in the package we will use.

pip install xhtml2pdf # Python 2 pip install --pre xhtml2pdf # Python 3

Lets setup our render class, we will be building a wrapper class that holds our logic for building our pdf. This file is render.py

We create a class called Render and build out a static method called render, this takes a string and dict as arguments.

We then use some django methods to get the template and render it using our dict argument.

The pisa.pisaDocument method accepts streams as parameters we need a source and destination. we encode our template to UTF-8 and parse that into a BytesIO stream and then use the reponse object we created to hold the output from pisa.

We then check for errors during the processing and return HttpResponse object, for success we specify we want the response.getValue() and set the content_type meta tag as ‘application/pdf’.

Lets build out our views.py

We implement a standard CBV, with just a get method, we build our params dictionary and return a Render.render() object. We don’t need to return a Httpresponse as this is handled by the Render.render method.

So now we need our template:

You may run into trouble pulling external stylesheets, ideally i would suggest you keep your styling inline.

Lets bind our view to a URL, in a real project i would create a urls.py as normal, however for this example i have just bound it to the main urls file.

path('render/pdf/', Pdf.as_view())

Lets give it a test, inside Chrome i get the following: