Converting Django templates with HTML and CSS into downloadable PDF files

Struggling to convert HTML & CSS into a downloadable PDF page using Django and Weasyprint. The current tutorial isn't working as expected - I need the PDF to render the current page when the user clicks on the download button, automatically downloading with read-only privileges. This entire process is turning out to be more challenging than anticipated.

Weasyprint only converts a URL in Django to a PDF file, but I can't figure out how to link the download button to the Weasyprint view.

I might be overcomplicating things - any help would be greatly appreciated.

Here's an example of Weasyprint code:

 (code snippet) 

I set up a virtual environment on my PC exactly like the example provided, currently utilizing Bootstrap 4.

If there's a better way to achieve this, please share your insights :)

Moreover, I'm looking to target only the body tags for conversion to PDF, not the entire webpage.

Previously, I tried using this solution: https://codepen.io/AshikNesin/pen/KzgeYX, but it didn't work effectively.

*EDIT 2.0*

Switching to JavaScript now, I'm struggling with a script that doesn't create a PDF form upon clicking. Is there a way to ensure the JS function downloads only the selected ID within the div, without affecting resolution or scale? (To avoid rendering unnecessary content)

https://jsfiddle.net/u4ko9pzs/18/

Any suggestions or advice would be highly appreciated.

Answer №1

After experimenting with django-wkhtmltopdf and weasyprint, I found that while weasyprint is more versatile when it comes to CSS, it still doesn't perfectly replicate the browser's rendering. The results were not satisfactory, especially when dealing with complex layouts.

For my specific requirement of creating a pixel-perfect 'certificate' PDF with an SVG background, puppeteer turned out to be the solution as it ensured compatibility with minimal modifications to the CSS. However, using puppeteer requires Node.js (which I was already using for asset compilation).

Puppeteer CLI:

npm i- puppeteer-pdf

Install the Django wrapper

pip install django-puppeteer-pdf

Include the Node puppeteer CLI start command in your settings:

PUPPETEER_PDF_CMD = 'npx puppeteer-pdf'

and create view:

from puppeteer_pdf import render_pdf_from_template
from django.http import HttpResponse, 
import os

# Rendering code 
context = {
    'data': 'test data'
}

output_temp_file = os.path.join(settings.BASE_DIR, 'static', 'temp.pdf')

pdf = render_pdf_from_template(
    input_template='path to template in templates dir'
    header_template='',
    footer_template='',
    context=context,
    cmd_options={
        'format': 'A4',
        'scale': '1',
        'marginTop': '0',
        'marginLeft': '0',
        'marginRight': '0',
        'marginBottom': '0',
        'printBackground': True,
        'preferCSSPageSize': True,
        'output': output_temp_file,
        'pageRanges': 1
    }
)
#you can remove temp file now or collecte them and run some crone task.(performance)
if os.path.exists(output_temp_file):
    os.remove(output_temp_file)
else:
    # raise error or something

filename = f'filename={'your donwload file name'}.pdf'

response = HttpResponse(pdf, content_type='application/pdf;')
response['Content-Disposition'] = filename

To preserve original colors, add this to your CSS:

html{
  -webkit-print-color-adjust: exact;
}

When using 'preferCSSPageSize', control page size and margins like so:

@page {
  size: A4;
  margin: 0 0 0 0;
}

Answer №2

Try using the whkhtmltopdf tool in Django for easy conversion of pure HTML to PDF.

Install django-wkhtmltopdf by running: pip install django-wkhtmltopdf

For more information, visit

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Struggling to get the Content Security Policy (CSP) to function properly within Next.js

I have been working on a NextJS project and I am currently facing a challenge in setting up secure headers in the next.config.js file of my project. I have attempted various solutions found online, but unfortunately, none of them seem to be working for me ...

Eliminate any HTML content using Jsoup while retaining the text lines

I am working with a String that contains e-mail content, and my goal is to eliminate all HTML coding from this String. This is the current code I have: public static String html2text(String html) { Document document = Jsoup.parse(html); document = ...

Tips for transitioning from an old link to a new link within an MVC framework

Is there a way to redirect an old link to a new link in MVC? In Google search results, my old URL was cached as www.abcd.com/product?id=64 however, my new URL is now www.abcd.com/product/sample How can I set up a redirect so that when a user clicks on th ...

Why is it that filling a DataTable with a variable doesn't work, but when I input the same value into a PHP site and request it using AJAX, it suddenly works?

Contained within the variable named "test" is the following data: {"data":[{"HistChar_ID":"4","Vorname":"Garnier","Nachname":"de Naplouse"},{"HistChar_ID":"2"," ...

Below, the HTML contains my response API. I need to retrieve the value 355310 from this in order to set an environment variable in Postman

After receiving the response from the API, I share the picture as shown in the following link: https://i.sstatic.net/irL6Z.jpg ...

"the content does not occupy the entire space of the parent

My TableRow expands across the width of the screen, and within it is a ListView with a layout_width set to match_parent. However, the ListView does not expand properly. This issue arose when I added two buttons in the next TableRow. Even after setting the ...

Implementing setDoc with Firebase-Admin using Typescript in Firestore

I'm having issues with my code in config/firebase.ts: import { initializeApp, cert } from 'firebase-admin/app'; import { getFirestore } from 'firebase-admin/firestore' const firebaseAdminApp = initializeApp({ credential: cert( ...

Seasonal selection tool

I need a quarterly date picker feature, ideally using Angular. I am interested in something similar to the example shown below: https://i.stack.imgur.com/9i0Cl.png It appears that neither Bootstrap nor (Angular) Material have this capability. Are there a ...

Switching icons in a Vue framework when hovering over multiple elements

I'm looking to update the icon of a specific element on hover using Vue instead of JS/jQuery. Currently, my code is changing the icons of all four elements when hovered over: HTML: <div class="col-md-3"> <div class="welcome-latest"> ...

What is preventing me from specifying a specific position in my multi-dimensional array?

My goal is to create a 3D version of an L-System, but I'm having trouble declaring elements in my multidimensional array. Even when I try to assign values to specific positions, the elements don't seem to update properly. For instance, if I write ...

What could be causing ng-click to fail in dynamic HTML content?

I am currently working on a web application using AngularJS which includes a selection feature for master data. While everything is functioning correctly, I encountered an issue with creating a dynamic button inside a table and attaching an ng-click method ...

Dygraphs.js failing to display the second data point

My website features a graph for currency comparison using Dygraphs. Everything was working fine until I encountered this strange issue. https://i.stack.imgur.com/OGcCA.png The graph only displays the first and third values, consistently skipping the seco ...

determine the quantity and categorize them

I am currently utilizing python in conjunction with pymongo. Within a mongo collection, I am storing various messages from different countries. Each document contains a country short code to indicate its origin. How can I group these messages by country c ...

Attaching to directive parameters

I've been working on creating a draggable div with the ability to bind its location for further use. I'm aiming to have multiple draggable elements on the page. Currently, I've implemented a 'dragable' attribute directive that allo ...

Script function in Google Sheets HTML not being called

Within my Google app, I have the following HTML code that is supposed to call a function below. However, I am not getting any response. This script has been used consistently throughout my code until now. <div id= "right_column"> <p> ...

Oh no! It seems like the build script is missing in the NPM

https://i.stack.imgur.com/el7zM.jpg npm ERR! missing script: build; I find it strange, what could be causing this issue? Any suggestions? I have included the fullstack error with the package.json. Please also review the build.sh code below. Fullstack err ...

Using CSS, replicate the language menu found on GitHub

Is there a way to replicate GitHub's repositories language list using CSS alone? For instance, something similar to the image shown here: https://i.sstatic.net/Kd4iC.png I initially tried creating a list of div elements but I'm struggling to fi ...

Guide to generating a form field for each foreign key in a many-to-many connection within Django

I am struggling to figure out how to create a specific form in Django. Let me start by sharing my models with you: class Category(models.Model): name = models.CharField(max_length=200, unique=True) class Assessment(models.Model): name = models.C ...

The function parseFloat in Javascript can be used to subtract two numbers, returning an integer value

Apologies for the inconvenience, but I could really use some assistance. I attempted to convert a string into a decimal and was successful, although I encountered an issue: number = document.getElementById("totalcost").innerHTML; //String that rep ...

I am interested in utilizing Selenium to interact with a hyperlink within an HTML table

I am currently using the code snippet below to fetch data from the HTML structure provided: //findTables(driver); WebElement content = driver.findElement(By.id("tblTaskForms")); List<WebElement> elements = content.findElements(By.className("form-nam ...