Как сделать рендер генерированной html страницы в pdf в Django?

Не могу уже 3 день найти адекватное решение по переводу html в pdf на django, чтобы оно выглядело адекватно.

1) Решение на APi pdfcrowd

def pdf(request):
    if request.POST:
        chatvs = Competirors.objects.get(id = int(request.POST.get('competitor', '')))
        staff = Manager.objects.get(id = int(request.POST.get('manager', '')))

        business = Field.objects.get(id = int(request.POST.get('filed', '')))

        business = business.link.all().order_by('?')[0:3]
        
        context = {
            "chatvs" : chatvs,
            "staff" : staff,
            "business" : business,
        }

        tmpl = get_template('marketing/pdf.html', )
        html = tmpl.render(context)        
        
        # create an API client instance
        client = pdfcrowd.Client()
        
        # convert a web page and store the generated PDF to a variable
        pdf = client.convertHtml(html)
        
         # set HTTP response headers
        response = HttpResponse(content_type='application/pdf')
        response['Content-Disposition'] = 'attachment; filename="log.pdf"'
        response["Cache-Control"] = "max-age=0"
        response["Accept-Ranges"] = "none"

        # send the generated PDF
        response.write(pdf)
        return response


Выбивает все css/static объекты - получается убого. В итоге не работает.

2) Решение на reportlab - фактически приходится канвасом рисовать весь pdf-файлик. Нормальное решение, но в моем случае это не подходит, так как нужно решение для генерации большого числа различных pdf.

3) Решение на Pisa - а его больше нет. Сервис закрыли, пакеты удалили, и создатели теперь делают другую штуку.

4) Решение на PDFKit/wkhtmltopdf - принимают для своей работы url/file/string - но я так и не нашел способ, как передать в них страничку рендера, чтобы он его обработал и сохранил в pdf.

def pdf(request):
    if request.POST:
        chatvs = Competirors.objects.get(id = int(request.POST.get('competitor', '')))
        staff = Manager.objects.get(id = int(request.POST.get('manager', '')))

        business = Field.objects.get(id = int(request.POST.get('filed', '')))

        business = business.link.all().order_by('?')[0:3]
        
        context = {
            "chatvs" : chatvs,
            "staff" : staff,
            "business" : business,
        }

        tmpl = get_template('marketing/pdf.html', )
        html = tmpl.render(context) 

        #Как-то тут надо прикрутить pdfkit?


===

Есть способ заставить работать 4 способ, либо я пропустил еще что-то?
  • Вопрос задан
  • 1938 просмотров
Пригласить эксперта
Ответы на вопрос 4
sergey-gornostaev
@sergey-gornostaev Куратор тега Django
Седой и строгий
В прошлом году на одном из своих проектов столкнулся с этой задачей. Я много перелопатил и пришёл к выводу, что нет ни одной библиотеки, которая бы рендерила HTML в PDF со 100% точностью. В результате использовал xhtml2pdf (наследник Pisa), убив не мало времени на изучение особенностей его работы. Думаю, стоит посмотреть в сторону наследника xhtml2pdf - WeasyPrint.
Ответ написан
Комментировать
zelsky
@zelsky
А ведь можно прописать стили для print и уже по этим стилям генерировать пдф. Верно я вас понял ?
Ответ написан
Всем доброго дня, года 3 назад, тоже приходилось решать такую проблему, решил ее с использованием xhtml2pdf. Как сейчас обстоит дело с данным пакетом, сказать не могу.
from django.template.loader import get_template
from django.template import Context, RequestContext
import xhtml2pdf.pisa as pisa
import cStringIO as StringIO
import cgi

def render_to_pdf(template_src, context_dict, name_file):
    template = get_template(template_src)
    context = Context(context_dict)
    html = template.render(context)
    result = StringIO.StringIO()
    pdf = pisa.CreatePDF(StringIO.StringIO(html.encode("UTF-8")), result, encoding='UTF-8')
    if not pdf.err:
        # return http.HttpResponse(result.getvalue(), mimetype='application/pdf')
        response = HttpResponse(result.getvalue(), content_type='application/pdf')
        response['Content-Disposition'] = 'attachment; filename="' + name_file + '.pdf"'
        return response

    return http.HttpResponse(('We had some errors<pre>%s</pre>' % cgi.escape(html)))

def ajax_post(request, slug):
    if request.POST:
        query_text = request.POST["data"].encode("UTF-8")
        title = Document.objects.get(slug=slug).title

        return render_to_pdf('documents/entries1.html', {
            'pagesize': 'A4',
            'title': title,
            'test': query_text
        }, slug)
    else:
        return redirect('documents-create', slug=slug)


Шаблон родитель pdf.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>My Title</title>
        <style type="text/css">
            @page {
                size: {{ pagesize }};
                margin: 1cm;
                @frame footer {
                    -pdf-frame-content: footerContent;
                    bottom: 0cm;
                    margin-left: 9cm;
                    margin-right: 9cm;
                    height: 1cm;
                }
            }
            @font-face {
                font-family: "Open Sans";
                src: url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot?#iefix") format("embedded-opentype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.woff") format("woff"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.ttf") format("truetype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.svg#svgFontName") format("svg");
            }
            @font-face {
                font-family: "Open Sans";
                font-weight: 600;
                src: url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.eot?#iefix") format("embedded-opentype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.woff") format("woff"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.ttf") format("truetype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.svg#svgFontName") format("svg");
            }
            @font-face {
                font-family: "Open Sans";
                font-weight: bold;
                src: url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Bold-webfont.eot?#iefix") format("embedded-opentype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Bold-webfont.woff") format("woff"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Bold-webfont.ttf") format("truetype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Bold-webfont.svg#svgFontName") format("svg");
            }
            @font-face {
                font-family: "Open Sans Light";
                src: url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.eot?#iefix") format("embedded-opentype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.woff") format("woff"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.ttf") format("truetype"), url("//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.svg#svgFontName") format("svg");
            }
            body {
                color: #484848;
                font-family: 'Open Sans',Arial,Helvetica,sans-serif;
                font-size: 14px;
                text-align: left;
                line-height: 1.5em;
}

        </style>
    </head>
    <body>
        <div>
            {{ mylist|safe }}
        </div>
        <div id="footerContent">
            {%block page_foot%}
                Page <pdf:pagenumber>
            {%endblock%}
        </div>
    </body>
</html>

Шаблон в который передаем данные entries1.html
{% extends "pdf.html" %}

{% block title %}{{ title }}{% endblock %}

{% block content %}
      {{ test|safe }}
{% endblock %}

{%block page_foot%}
    я страница {{block.super}}
{%endblock%}
Ответ написан
@alex-busov
разработчик
Мне понравился этот пакет: https://github.com/incuna/django-wkhtmltopdf
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы