Not as easy as you think. There’re quite a few packages available for that, and yet!
Install packages:
pip install pdfkit
sudo apt install wkhtmltopdf
Say, you want to print a listing of holidays local to Moscow and give out to people on the street. Say, there’s a model.py like that:
class Holiday(models.Model):
summary = models.TextField()
date = models.DateField()
class City(models.Model):
name = models.CharField(max_length=100)
holidays = models.ManyToManyField(Holiday)
Let’s be clear, this is not an ideal structure, it highly depends on what your app is about. But for the sake of a simple example, let’s proceed.
Then, you will need a view to generate HTML and get PDF. In views.py craft a view function for that:
import pdfkit
from io import BytesIO
from django.template.loader import get_template
from django.http import HttpResponse
city_name = 'Moscow'
template_src = 'report/test.html'
context = {
'city': city_name,
'holidays': [
{'summary': x.summary, 'date': x.date} for x in
City.objects.get(name=city_name).order_by('date')
]
}
def get_pdf(request):
template = get_template(template)
html = template.render(context)
options = {
'page-size': 'A4',
'margin-top': '0in',
'margin-right': '0in',
'margin-bottom': '0in',
'margin-left': '0in',
'encoding': "UTF-8",
'no-outline': None
}
pdf = pdfkit.from_string(html, False, options)
response = HttpResponse(pdf, content_type='application/pdf')
return response
Register it somewhere in urls.py and enjoy. You may want to have the page itself to change styles in browser’s Developer Mode. So make a view, add it to the bottom of views.py and and register it as well:
from django.shortcuts import render
def listing(request):
return render(request, template, context)
It is a standard view. For HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Holidys for {{ name }} city</title>
</head>
<body>
<div>
<h2>Holidys for {{ name }} city</h2>
<p>Be prepared for this festive season.</p></div>
<div
{% for x in holidays %}
<p class="inner">{{ forloop.counter }}. <b>{{ x.date }}.</b> {{ x.summary }}</p>
{% endfor %}
</div>
</body>
</html>
To sum up, get_pdf() will generate you a pdf of a page and listing() is a live version of that page – use it to see changes you do to the styles and layout.
This code is available at my GitHub if you are interested.