Rendering PDF from django templates
Rune Hansén Steinnes-Westum
2 min read
Again, more of a note to self than a real tutorial. I'll try not to make it obtuse.
Your pod/container must have a compatible wkhtmltopdf installed (yes, I'm weaned off of docker. It's podman all the way baby!). This is very important and something that has tripped me up more than once.
Other than that just follow the installation and setup tutorials of django, django rest framework and django-dbtemplates to get the settings and urls in order.
Key points
- Templates can be files on disk or stored in database
- If the template renders on the server, it will render as PDF
- PDF renders extremely true to the template
The files
requirements.txt
django
djangorestframework
pdfkit
# django-dbtemplates
# pip package lags behind
git+https://github.com/jazzband/django-dbtemplates.git#egg=django-dbtemplates
serializers.py
from dbtemplates.models import Template
from rest_framework import serializers
class PDFCreatorSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
template = serializers.CharField(max_length=256)
template_data = serializers.JSONField()
filestore_data = serializers.JSONField()
class FileStoreResponseSerializer: # Topic for another blog post
...
class TemplateSerializer(serializers.ModelSerializer):
class Meta:
model = Template
fields: str = "__all__"
views.py
from io import BytesIO
import uuid
import json
from typing import Tuple
from django.conf import settings
from django.http import HttpRequest
from dbtemplate.models import Template
from rest_framework import viewsets, permissions
from rest_framework.response import Response
from . import serializers
class RenderPDFTemplate(viewsets.ViewSet):
serializer_class = serializers.PDFCreatorSerializer
def create(self, request: HttpRequest) - > Response:
pdf, filename = self.create_pdf_from_template(
request.POST.get("template_data", ""),
request.POST.get("template", "")
)
.
.
. do file store stuff..
return Response(...)
def create_pdf_from_template(self, data: str, template_name: str) -> Tuple[BytesIO, str]:
data = json.loads(data)
data.update({"base": settings.BASE_DIR.parent.parent})
template = get_template(template_name=template_name)
outfile = uuid.uuid1().hex + ".pdf"
html = template.render(data)
options = {
"page-size": "A4",
"margin-top": "0.55in",
"margin-right": "0.25in",
"margin-bottom": "0.25in",
"margin-left": "0.25in",
"encoding": "UTF-8",
"quiet": "",
"enable-forms": None,
"enable-local-file-access": "",
}
pdf = pdfkit.from_string(html, False, options)
return (pdf, outfile)
class BaseModelViewSetWithPermissions(viewsets.ModelViewSet):
"""CRUD"""
permission_classes = (permissions.IsAuthenticated | permissions.IsAdminUser,)
class TemplateViewSet(BaseModelViewSetWithPermissions):
queryset = Template.objects.all()
serializer_class = serializers.TemplateSerializer
To test it, create a client
import requests
import json
URL = "https://yourdjangoserver/renderpdf/"
TOKEN = "The DjangoRestFrameworkToken you created in admin"
HEADERS = {"Authorization": f"{TOKEN}"}
DATA = {
"template_name": "yourtemplate.html" ,
"template_data": json.dumps({"somehing": "else", "more": "of the same", "date": "2022-02-02"}, default=str),
}
res = requests.post(URL, headers=HEADERS, data=DATA, verify=False)
Simple as that!
0
Subscribe to my newsletter
Read articles from Rune Hansén Steinnes-Westum directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by