Найти в Дзене
В неизвестность

Django & WeasyPrint: почему в pdf не отображаются картинки?

Потому что weasyprint это не xhtml2pdf!

Не надо пытаться передать ему данные о картинке во вьюшке, он такое не понимает.

Печатаем html в pdf так, чтобы слои были
Печатаем html в pdf так, чтобы слои были

Когда мы печатаем pdf из html'ки с помощью xhtml2pdf, мы в питоновскую функцию во views.py передаём данные. Это выглядит примерно так:

views.py:

from xhtml2pdf import pisa
from urllib.parse import quote

def download_pdf(request, pk):
winner = Winner.objects.get(pk=pk)
template_path = 'magicflot/pdf.html'
back_full = 'https://кириллический-домен-который-захотел-заказчик.рф/static/pdf/back_full.png'
e_back_full = quote(back_full.encode('utf-8'), safe='/')

context = {
'winner': winner,
'e_back_full':e_back_full,
}
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="certificate_{winner.last_name}_{winner.first_name}.pdf"'
template = get_template(template_path)
html = template.render(context)
pisa_status = pisa.CreatePDF(html, dest=response)
if pisa_status.err:
return HttpResponse('<pre>' + html + '</pre>')
return response

Ну, а в html у нас в нужном месте переменная:

<img src=' {{ e_back_full }} '>

Если надо напечатать что-то простое, xhtml2pdf - ок. А если что-то посложнее - проблема: оно глупое, слоёв z-index'ов не понимает. Считает, что <body></body> у него вокруг каждой таблички.

WeasyPrint - умная котенька, распечатает все ваши хитрые css.
Во views.py мы передаём только данные победителя викторины, которые будем на сертификате печатать.

views.py:
from weasyprint import HTML
def download_pdf(request, pk):
winner = Winner.objects.get(pk=pk)
template_path = 'myproject/pdf.html'


context = {
'winner': winner,
}

html_string = render_to_string(template_path, context)

pdf_file = HTML(string=html_string, base_url=request.build_absolute_uri()).write_pdf()

response = HttpResponse(pdf_file, content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="certificate_{winner.last_name}_{winner.first_name}.pdf"'

return response

А html файл выглядит вот так. Я засунула стили прямо в него, но можно подгружать из отдельного css'a, не принципиально.

{% load static %}
<!doctype html>
<html lang="en">
<head>
<style media="all" type="text/css">
body {
margin: 0;
padding: 0;
color: #091e3d;
font-family: "M PLUS Rounded 1c", sans-serif;
font-weight: 400;
font-style: normal;

}
.wrapper{
position: absolute;
z-index: 999;
background: transparent;
}
.background-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -5;
}
</style>

</head>

<body>
<img class="background-image" src="{% static 'pdf/back_full.png' %}" />
<div class='wrapper'>
/* Весь контент */
<h2>{{ winner.first_name }} {{ winner.last_name }}</h2>
</div>
</body>

Написала эту статью, потому что тупила 2 дня, прежде чем поняла, почему у меня картинки в pdf'ке не отображаются. Проблема была настолько глупая, что даже обидно.
Наверное, буду писать что-то ещё в таком же ключе. Вдруг кому-нибудь пригодится)