Как сгенерировать pdf из кастомного html (Django Templates), чтобы работало стабильно?
Продуктовая задача бытовым языком
Сделать в админке сайта на Django автоматический генератор красивых презентаций в pdf по шаблону с дизайном. Сценарий: юзер руками в админке собирает что-то вроде стратегии (последовательного набора определенных элементов), жмет кнопку "Сгенерировать презентацию" и у него(нее) скачивается файлик pdf с красивой презентацией, где в каждый слайд нужным образом раздаются разнообразные данные: тексты, цифры, даты, заголовки и так далее, а в начале и в конце - красивые слайды со статичным неизменяющимся текстом.
В презентации есть следующие элементы:
1. Нестандартный шрифт (подгружается файлом)
2. Фоновые изображения
3. Сложные css-стили
4. Своеобразная верстка (несколько колонок, выравнивание элементов относительно друг друга, что-то типа инфографики в виде таймлайна/диаграммы Ганнта)
5. Кликабельные ссылки на внешние сайты, которые формируются по определенному макросу.
Пробуем сделать функционал через wkhtmltopdf + pdfkit, но возникают сложности: расходится генерация на локалке и продакшене, иногда генерация ломается. Плюс эти библиотеки не поддерживают все нужные нам css-свойства, т.е. ее возможностей не хватает для наших задач. Хотя дизайн шаблона абсолютно не космический, скорее базовый.
Что пробовали
Отказались от pypdf и xhtml2pdf из-за ограничености стилей.
Есть ли более стабильное решение с поддержкой css3 и html5? И вообще, что посоветуете?
Наш стек - python3.9 + Django 3.
Дополнительно:
запускать chromium не пробовали?
Ответы:
Генерация pdf боль, а нормального конвертера из html я вообще не видел, в итоге проще всего оказалось сделать генерацию через pdfmake на js, по факту потребуется переделать свои шаблоны в описание на json, а от "Сложные css-стили" скорее придется отказаться. Либо отрисовывайте на более низком уровне тем же ReportLab
- все по делу
- Нормального конвертера из HTML в статическую картинку (хоть растровую, хоть векторную) не будет до тех пор, пока нет нормального HTML, однозначно описывающего эту картинку и не позволяющего ей поехать в зависимости от браузера, разрешения, доступных шрифтов и прочей фазы луны.
То есть, скорее всего - никогда.
Там, где кровь из носу нужно красиво на выходе - имеет смысл напрячься на входе и конвертировать в PDF не HTML, а SVG, например. Поскольку в собственно генерации PDF никакой особенной боли, кроме "shit in - shit out", нет. - Adamos,
Нормального конвертера из HTML в статическую картинку (хоть растровую, хоть векторную) не будет до тех пор, пока нет нормального HTML, однозначно описывающего эту картинку и не позволяющего ей поехать в зависимости от браузера, разрешения, доступных шрифтов и прочей фазы луны.
Вообще то есть стандартные штатные свойства/медиа запросы цсс для вывода на печать, чего вполне достаточно для реализации такой задачи. Просто не надо ее доверять клиентсайду ))
- ThunderCat, подозреваю что там накрутили красивостей, что с печатью тоже будет всё плохо.
Masha_Masha23 а если вообще отказаться от pdf и сделать html презентации? есть же фреймворки, например reveal.js
- Everything_is_bad, Все там нормально, мы так делали отчеты на 12-15 страниц с графиками, картинками, шрифтами и рюшечками. Один раз все настроили, отладили и работало как часики.
При этом 6 других инструментов оказались абсолютно нерабочими, или не выдающими приличного результата.
Накрученность на стороне клиента не победить, так как клиент по умолчанию криворукий м**дак (не по тому что всегда, а по тому что так должен думать нормальный программист), соответственно доверять нормальный рендер можно только бэкенду.
- ThunderCat, я так понимаю, ваша история успеха в том, что вы вместо разнообразных браузеров пользователей запускали рендеринг на одном браузере, который работал у вас же на сервере. Давая один и тот же результат.
Но я не уверен, что этот результат будет так же стабилен при переносе сайта на другой сервер и смене версии того Хромиума.Просто я помню, как в полиграфическом (!) Пижамкере ранних версий компоновка зависела от... разрешения принтера, установленного в системе по умолчанию. Причем зависела не при печати, а именно при открытии документа. Так что один и тот же файл на двух машинах открывался по-разному.
- Adamos,
Но я не уверен, что этот результат будет так же стабилен при переносе сайта на другой сервер и смене версии того Хромиума.
Тогда, по вашей логике, вообще не стоит заниматься разработкой, мало ли что перестанет работать при переносе с сервера на сервер... версия апача или питона сменится и - ага! Все пропало... Так то работа с принтером через хеадлесс хром хорошо контролируется и не сильно зависит от чего бы то ни было, так как все параметры "принтера" вы задаете сами, а правильный цсс под печать дает хорошую повторяемость.
- ThunderCat, ThunderCat, спасибо вам за ответы и комментарии по моему вопросу! Клиентсайду и не хотим доверять, при такой реализации вечно все идет не так и ломается) Пока крутили, решили пойти этим же путем: генерим пдфку в докере, результат загружается в обжект сторейдж и далее юзер просто скачивает готовый файл.
Selenium
https://copyprogramming.com/howto/python-selenium-...
тоже с сзъянами, ну а как... иначе весь стек под себя - никаких прогеров и денег не хватит
- Спасибо большое за ответ! Изучим)
1) Берем хеадлесс хром
2) скармливаем ему хтмл на печать в пдф с сохранением в файл
3) Готовый файл отдаем пользователю
3) Профит, все красиво, зайчики, графики, картинки...
При этом для отладки достаточно в хроме нажать ctrl+p и сразу увидеть где косяки с разметкой, как оно выглядит и вообще...
Нюансы:
1) хтмл должен быть заточен под вывод на печать, цсс для принт медиа специфичен, но не особо сложен
2) Для серверного хорма цсс/жс/картинки должны содержать полный локальный путь до файла
3) Есть некоторый нюанс с яваскриптами, работающими "не мгновенно", иногда надо поиграться с задержкой, там в параметрах оно настраивается.
Пример
- Спасибо вам)
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для генерации PDF из кастомного HTML, используя Django Templates, можно воспользоваться библиотекой под названием WeasyPrint. WeasyPrint позволяет создавать PDF документы из HTML и CSS, сохраняя все стили и макеты страницы.
Для начала, убедитесь, что у вас установлен WeasyPrint. Вы можете установить его с помощью pip:
pip install WeasyPrint
Далее, вам необходимо создать представление в Django, которое будет отображать ваш кастомный HTML шаблон. В этом представлении вы можете использовать функцию WeasyPrint HTML, чтобы преобразовать HTML в PDF.
Пример представления:
from django.http import HttpResponse from weasyprint import HTML def generate_pdf(request): html_template = 'your_template.html' pdf_file = 'output.pdf' html = HTML(string=render_to_string(html_template)) html.write_pdf(pdf_file) with open(pdf_file, 'rb') as pdf: response = HttpResponse(pdf.read(), content_type='application/pdf') response['Content-Disposition'] = 'filename="output.pdf"' return response
Не забудьте заменить 'your_template.html' на путь к вашему HTML шаблону.
Теперь, когда вы вызываете представление generate_pdf, оно должно сгенерировать PDF документ из вашего кастомного HTML шаблона и вернуть его как ответ.
Это простой способ генерации PDF из кастомного HTML с использованием Django Templates. Не забудьте настроить все пути к файлам и обработать возможные ошибки для стабильной работы вашего приложения.