How to Use PhantomJS for Generating Reports in Django

by Yaseen Dar

PhantomJS is a scripted, headless browser (a browser without Graphical User Interface) used for automating web page interactions. It provides a JavaScript API enabling automated navigation, screenshots, user behavior, and assertions making it a common tool used to run browser-based unit tests in a headless system like a continuous integration environment. Since PhantomJS is using WebKit, a real layout and rendering engine, it can capture a web page as a screenshot. PhantomJS can render anything on the web page, it can be used to convert contents not only in HTML and CSS, but also SVG and Canvas, so any stuff that can be showed in the web page can be rendered as pdf with the help of PhantomJS.

Install PhantomJS

On OSX use brew to install phantomjs

brew install phantomjs

Now let’s take a look at how to use phantomjs inside django view to render html page as pdf. We will start a simple django project namely ‘proj’ and add a reports app in it.

django-admin startproject proj

python manage.py startapp reports

Add reports under INSTALLED_APPS un settings.py

Now copy convertpdf.js into your  django project this is the file which will be used by Phantomjs, take screenshots of the html rendered in browser.

#convertpdf.js

var page = require('webpage').create(),

    system = require('system'),

    address, output, size;

page.paperSize = {

  width: '8in', height: '9.5in', 

  orientation: "portrait"

};

if (system.args.length < 3 || system.args.length > 5) {

    console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');

    console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');

    phantom.exit(1);

} else {

    address = system.args[1];

    output = system.args[2];

    page.viewportSize = { width: 1024, height: 770 };

    if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {

        size = system.args[3].split('*');

        page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }

                                           : { format: system.args[3], orientation: 'portrait', margin: '1cm' };

    }

    if (system.args.length > 4) {

        page.zoomFactor = system.args[4];

    }

    page.open(address, function (status) {

        if (status !== 'success') {

            console.log('Unable to load the address!');

            phantom.exit();

        } else {

            window.setTimeout(function () {

                page.render(output);

                phantom.exit();

            }, 500);

        }

    });

}

 

Create templates directory under reports and add two html file namely

#firstpage.html

<html>

<head>

  </head>

  <body>

    <p> click the link to download table myreport</p>

    <br>

    <a href='/myreport'>get my report</a>

  </body>

</html-->

 

#reportpage.html

<!--html>

  <head>

      <style>

          .lorem{

               width: 400px;margin:auto;

              font-size: 15px;

          }

      </style>

  </head>

  <body>

      <h3> My Report</h3>

      <div class="lorem" >

          <p style="text-align: justify;">Lorem Ipsum is simply dummy text of the printing and typesetting industry.

              Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,

              when an unknown printer took a galley of type and scrambled it to make a type specimen book.

              It has survived not only five centuries, but also the leap into electronic typesetting,

              remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset

              sheets containing Lorem Ipsum passages, and more recently with desktop publishing software

              like Aldus PageMaker including versions of Lorem Ipsum.</p>

      </div>

      <div class="lorem" ">

          <p style="text-align: justify;">Lorem Ipsum is simply dummy text of the printing and typesetting industry.

              Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,

              when an unknown printer took a galley of type and scrambled it to make a type specimen book.

              It has survived not only five centuries, but also the leap into electronic typesetting,

              remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset

              sheets containing Lorem Ipsum passages, and more recently with desktop publishing software

              like Aldus PageMaker including versions of Lorem Ipsum.</p>

      </div>

      

  </body>

</html-->

The overall project structure should look like this,

proj

├── proj
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
├
└── convertpdf.js
├── manage.py
├──reports
├── migrations
└── templates
├──firstpage.html
├── reportpage.html
├── __init__.py
├── tests.py
├── views.py
└── models.py
in views.py file add three views
from subprocess import Popen
from subprocess import PIPE
from subprocess import STDOUT
from django.views.generic import TemplateView, View
from django.http import StreamingHttpResponse
from django.core.servers.basehttp import FileWrapper
from proj.settings import BASE_DIR
class MyFirstView(TemplateView):
template_name = "firstpage.html"
   	def get(self, request):
        		return self.render_to_response({})
class MyReportView(TemplateView):
template_name = 'reportpage.html'
 	def get(self, request):
        		return self.render_to_response({})
class MyPdfView(View):

def get(self, request, *args, **kwargs):
        	      file_name = BASE_DIR + 'testreport.pdf'
        	      filefrom = BASE_DIR + '/convertpdf.js'
        	      url = 'http://' + request.get_host() + '/pdfreport'
        	      external_process = Popen(["/usr/local/bin/phantomjs", filefrom, url, file_name],
                                 stdout=PIPE, stderr=STDOUT)
       external_process.wait()
        return_file = FileWrapper(open(file_name, 'r'))
        download_file_name = 'myreport'
        response = StreamingHttpResponse(return_file, content_type='application/force-download')
        response['Content-Disposition'] = 'attachment; filename= %s.pdf' % download_file_name
        return response

Now inside your urls.py file add this line,

from reports import views

And inside urlpatterns list add

url(r'^$', views.MyFirstView.as_view()),
    url(r'^pdfreport$', views.MyReportView.as_view()),
    url(r'^myreport$', views.MyPdfView.as_view()),

And we are done now. Run the project.

python manage.py migrate
python manage.py runserver

Go to your browser enter localhost:8000 and click to get ‘my report’ and your report will get downloaded. You can see full project here https://github.com/yaseendar/phantomjs-django.

Leave a Reply

Your email address will not be published. Required fields are marked *

Tools & Practices

Tools and Technologies we use at Applied

Contact us now

Popular Posts