Home / Blogs

How to Generate PDF Files in Python with Xhtml2pdf

Django
·

January 5, 2024

how-to-generate-pdf-files-in-python-with-xhtml2pdf

PDF files are a popular file format that maintains document formatting across different platforms. Unlike other file types that may change appearance on different devices, PDFs look the same regardless of the operating system, software, or hardware used to view them. This makes PDFs ideally suited for sharing documents electronically. The xhtml2pdf library provides a straightforward way to convert HTML content into PDF format. It is completely written in Python and can be used on any platform. This library converts HTML and CSS into PDF format, providing a way to programmatically create PDFs. It can be integrated with Django to make the rendered web pages into PDF documents. This can be useful when you want to provide users with the ability to download web content in PDF format.

To read more about removing the background of an image using rembg in Python, refer to our blog How to Remove the Background of Image Using Rembg in Python

In this blog, let’s explore how to download a webpage into a PDF document using Django.

The Code Implementation

First, create a virtual environment for the Django web application and install Django, install all the requirements, and start the project —check out our ‘Django Project Setup‘ blog for a guide. After creating the app and configuring the views, URLs,  and template, install the xhtm2pdf package into the virtual environment.

To install the Xhtml2pdf package, open the terminal activate the virtual environment, and execute the following command:

pip install xhtml2pdf

This will download and install the latest stable version of the xhtml2pdf package, along with all additional requirements, into the virtual environment.

After installing the package, we want to create a new view and URL for converting the webpage into PDF.

The below function will change the html template into PDF.

import io 
from xhtml2pdf import pisa 
from django.template.loader import render_to_string
from django.http import HttpResponse


def generate_pdf(template_path, context):
    html = render_to_string(template_path, context)

    result = io.BytesIO()
    pdf = pisa.pisaDocument(io.BytesIO(html.encode("utf-8")), result)

    if not pdf.err:
        response = HttpResponse(result.getvalue(),  content_type="application/pdf")
        response[
            "Content-Disposition"
        ] = f'''attachment;filename="{context["employee"]}'s payslip for       {context["range"]}.pdf"'''
        return response
    return None

The code begins by importing the necessary libraries. Import the ‘io’ module for working with input/output streams. Importing ‘pisa’ from ‘xhtml2pdf’ plays a pivotal role in converting HTML to PDF and ‘render_to_string’, it effectively renders a template to a string.

generate _pdf is the custom function used in this example. It requires two parameters: template_path and context.

The template name parameter is the path of the HTML file to be changed to PDF, and context refers to the dictionary containing data that will be passed to the template.

html = render_to_string(template_path, context)

The render_to_string function is saved to a variable named html. The ‘render_to_string’ function is used to render the specified Django template (template_path) to HTML. The ‘context’ dictionary contains the data to be used in the template.

result = io.BytesIO()
    pdf = pisa.pisaDocument(io.BytesIO(html.encode("utf-8")), result)

An output stream (result) is created using the io.BytesIO() class and saved into a variable named result.

The ‘pisa.pisaDocument’ function is then used to convert the HTML content (encoded in UTF-8) to a PDF document. The result is stored in the result stream.

 if not pdf.err:
        response = HttpResponse(result.getvalue(),  content_type="application/pdf")
        response[
            "Content-Disposition"
        ] = f'''attachment;filename="{context["employee"]}'s payslip for       {context["range"]}.pdf"'''
        return response

‘if not pdf.err’ check if there were any errors during PDF generation. If no errors occurred, create an HttpResponse object with the PDF content.

Set the content type to “application/pdf” to indicate that it’s a PDF file.

response[“Content-Disposition”] is used to specify the filename for the downloaded PDF. In this example, the name of the employee with the payslip range is given as the file name.

 return None

If there were errors during PDF generation (‘If not pdf. err’ function fails), the function returns None.

This function is designed to be used in a Django view. When the view is called, it renders a template to HTML, converts the HTML to a PDF document, and returns an HTTP response containing the PDF for the user to download.

To read more about compressing images using Python in a Django Project, refer to our blog How to Compress Images Using Python in a Django Project

Conclusion

In this blog, we explored the integration of the xhtml2pdf library with Django, allowing the generation of PDF documents from HTML templates. The tutorial covered setting up a Django project, installing xhtml2pdf, and implementing a custom function to convert HTML content to PDF. This capability is valuable for scenarios where users need to download web content, such as generating customized payslips. The provided generate_pdf function encapsulates the process, offering a practical solution for dynamically creating and delivering PDFs in a Django web application.

Horilla Editorial Team Author

Horilla Editorial Team is a group of experienced writers and editors who are passionate about HR software. We have a deep understanding of the HR landscape and are committed to providing our readers with the most up-to-date and informative content. We have written extensively on a variety of HR software topics, including applicant tracking systems, performance management software, and payroll software etc. We are always looking for new ways to share our knowledge with the HR community. If you have a question about HR software, please don't hesitate to contact us.