pythonnode.jspython-3.xwkhtmltopdfhtml-pdf

How to generate a PDF with a given template, with dynamic data in Python or NodeJS to be deployed on AWS


Looking for recommendation of a library in Python(first preference) or NodeJS that can generate a pdf file preferably from dynamic html template to be run in AWS. Requirement is to generate invoice pdf to be sent to customers.

Have come across below 2 Node libraries:

Here we might have to deal with numbers for X and Y.

Better approach would be something where we can simply use html/css to generate template with placeholders which can be replaced with dynamic data(coming from database query). Any suggestions would be appreciated.

Thanks!


Solution

  • This approach worked for me in Python using below libraries:

    Jinja2 - for generating HTML with custom data

    xhtml2pdf - for generating PDF from HTML

    Consider within your PROJECT DIR, there is a template file(invoice.html) and python file(pdf_generator.py)

    pdf_generator.py

    from xhtml2pdf import pisa 
    import jinja2
    templateLoader = jinja2.FileSystemLoader(searchpath="./")
    templateEnv = jinja2.Environment(loader=templateLoader)
    TEMPLATE_FILE = "invoice.html"
    template = templateEnv.get_template(TEMPLATE_FILE)
    
    # This data can come from database query
    body = {
        "data":{
            "order_id": 123,
            "order_creation_date": "2020-01-01 14:14:52",
            "company_name": "Test Company",
            "city": "Mumbai",
            "state": "MH",
        }
    }
    
    # This renders template with dynamic data 
    sourceHtml = template.render(json_data=body["data"]) 
    outputFilename = "invoice.pdf"
    
    # Utility function
    def convertHtmlToPdf(sourceHtml, outputFilename):
        # open output file for writing (truncated binary)
        resultFile = open(outputFilename, "w+b")
    
        # convert HTML to PDF
        pisaStatus = pisa.CreatePDF(
                src=sourceHtml,            # the HTML to convert
                dest=resultFile)           # file handle to receive result
    
        # close output file
        resultFile.close()
    
        # return True on success and False on errors
        print(pisaStatus.err, type(pisaStatus.err))
        return pisaStatus.err
    
    if __name__ == "__main__":
        pisa.showLogging()
        convertHtmlToPdf(sourceHtml, outputFilename)
    

    invoice.html

    <!DOCTYPE html>
    <html lang="en">
    <body>
    Name: {{ json_data.company_name }} <br>
    City/State: {{ json_data.city }}, {{ json_data.state }} <br>
    Date: {{ json_data.order_creation_date }} <br>
    Order ID: {{ json_data.order_id }} <br>
    </body>
    </html>