Django CBV:以编程方式将HTML页面保存到服务器上的PDF文件

时间:2018-03-11 21:17:28

标签: python django python-3.x django-views

访问相关网址时,会显示一个html网页。我需要以编程方式将此html页面保存到服务器上的pdf文件中。

views.py

class PdfView(DetailView):
    model = TheModel
    template_name = 'pdf.html'

urls.py

urlpatterns = [
    url(
        r'^(?P<pk>[0-9]+)/$',
        PdfDataView.as_view(),
        name='pdf-data',
    ),
]

3 个答案:

答案 0 :(得分:1)

尝试以下方法。虽然它通过响应向最终用户提供服务文件,但是将其修改为在服务器上写入文件应该很容易:

功能视图:

def pdf_sticker(request, pk):
    spot = get_object_or_404(Spot, pk=pk)
    if spot.is_certificated:
        pdf, result = render_to_pdf(
            'www/pdf_sticker.html',
            {
                'pass_smth': 'needed_in_render',
                'MEDIA_ROOT': settings.MEDIA_ROOT,
                'STATIC_ROOT': settings.STATICFILES_DIRS[0],
                'pagesize': 'A6',
            }
        )
        if not pdf.err:
            return HttpResponse(result.getvalue(), content_type='application/pdf')
        return HttpResponse('We had some errors')
    else:
        raise Http404

辅助方法:

from io import StringIO, BytesIO
from xhtml2pdf import pisa

from django.template.loader import get_template


def render_to_pdf(template_src, context_dict):
    template = get_template(template_src)
    html = template.render(context_dict)
    result = BytesIO()
    pdf = pisa.pisaDocument(
        StringIO(html),
        dest=result,
        encoding='UTF-8'
    )

    return pdf, result

模板:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>


        <title>Sticker for certificated spot</title>
        <style type="text/css">
                 @font-face {
                    font-family: "Lobster";
                    src: url("{{ STATIC_ROOT }}/font/Lobster-32.ttf");
                    font-weight: normal;
                    font-style: normal;
                }
                @font-face {
                    font-family: "Lato";
                    src: url("{{ STATIC_ROOT }}/font/Lato-Hairline.ttf");
                    font-weight: 100;
                    font-style: thin;
                }
                @font-face {
                    font-family: "Nobile";
                    src: url("{{ STATIC_ROOT }}/font/Nobile-34.ttf");
                    font-weight: normal;
                    font-style: normal;
                }

                @page {
                    size: {{ pagesize }};
                    margin: 0.5cm;
                }

        </style>
    </head>
    <body>
        <center>
            <img src="{{ STATIC_ROOT }}/{{ SPOT_PROJECT_NAME }}/certificate.png" height="260px">
            <p style="font-family:Lobster;">
                <span style="font-size:60px;">
                    {% settings_value "SPOT_PROJECT_SUBJECT" %}<br>
                </span>
                <span style=" font-size:32px;">
                    friendly spot!
                </span>
                <br>
                <table>
                    <tr>
                        <td colspan=2>
                             <img src="http://{{BASE_HOST}}{% url 'www:qrencode_link' pk=spot.pk size=4 %}">
                        </td>
                    </tr>
                    <tr>
                        <td colspan=2 height=5></td>
                    </tr>
                    <tr>
                        <td colspan=2>
                            <span style="font-family:Nobile; font-size:15px;">
                            Powered by: <img src="{{ STATIC_ROOT }}/{{ SPOT_PROJECT_NAME }}/logo.png" height="50px"> </span>
                            <span style="font-family:Lobster; font-size:25px;">
                                    {{ SPOT_PROJECT_NAME }}
                            </span>
                        </td>
                    </tr>
                </table>
            </p>
        </center>
    </body>
</html>

为Python 3.6,Django 2.0工作。

图书馆版本:

Django==2.0.2
xhtml2pdf==0.2b1

关于将其写入服务器上的本地文件的部分,这可能会有所帮助:

http://xhtml2pdf.readthedocs.io/en/latest/usage.html#using-with-python-standalone

答案 1 :(得分:1)

以下解决方案在将HTTP响应提供给浏览器之前,在HTTP请求期间保存网页的pdf版本。

我使用了weasyprint,因为它设法开箱即用地处理unicode字符。

<强> views.py

from weasyprint import HTML

class PdfView(DetailView):
    model = TheModel
    template_name = 'pdf.html'

    def get(self, request, *args, **kwargs):
        template_response = super().get(self, request, *args, **kwargs)
        HTML(string=template_response.rendered_content).write_pdf(
            '/path/to/test.pdf',
            stylesheets=['/path/to/pdf.css']
        )
        return template_response

在视图之外的更好的解决方案是使用requests来获取HTML页面,然后创建pdf文件。它更好,因为服务器不必等待创建pdf,可能阻止等待服务器的其他请求:

>>>import requests
>>>resp = requests.get('http://my-url/object_id')
>>>HTML(string=resp.content).write_pdf('/path/to/test.pdf', stylesheets=['/path/to/pdf.css'])

答案 2 :(得分:1)

此功能对我有用。

def render_to_pdf(template_src, context_dict={}):
        template = get_template(template_src)
        html = template.render(context_dict)
        result = BytesIO()
        pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
        if not pdf.err:
            f = open('test2.pdf', 'wb')
            myfile = File(f)
            myfile.write(result.getvalue())
            return HttpResponse(result.getvalue(), content_type='application/pdf')
        return None