python web导出排版的pdf文件

阿凡达2018-07-27 08:54

动机

项目开发中,经常碰到:

将数据从数据库中导出,生成excel/pdf等格式的文件

生成excel比较简单,有:

tablib
xlwt(可以实现复杂的功能,如合并单元格、设置单元格样式)

等库可以实现。

生成pdf也简单,但难的是:

生成有排版格式要求的pdf

解决

思路

html很用以去做排版,那么要生成有排版格式要求的pdf, 只要:

1. 从数据库中获取数据
2. 使用定义好的html模板,用数据去填充页面,获得html字符串
3. 把html字符串转为pdf

关于第二点,可以使用页面渲染引擎去做,java里面可以使用:

beetle
freemarker
velocity

等引擎。python中可以使用 jinja2 Miko

等, 本文使用jinja2

关于第三点,本文使用xhtml2pdf库。(本文的例子基于Python 2.7、flask的框架)

xhtml2pdf 安装

pip install xhtml2pdf
pip install html5lib==1.0b8

中文字体问题

xhtml2pdf默认不支持中文字体,所以需要下载中文字体,比如:

宋体: simsun

同时要指定html页面的charset, 如:

<meta charset='utf8'/>

页面模板

路径是:

templates/test.html
<html>
    <head>
        <meta charset='utf8'/>
        <style type="text/css">
        @font-face {
           font-family: simsun;
           src: url("{{font_path}}");  /* 字体路径 */
        }   
        body {
           font-family: simsun;
        }   
        </style>
    </head>
    <body>
        欢迎, {{name}}
    </body>
</html>

后端代码

#!/usr/bin/env python
#! -*- coding: utf-8 -*-

from jinja2 import PackageLoader, Environment

from flask import Flask, current_app, url_for, make_response
import xhtml2pdf.pisa as pisa
from cStringIO import StringIO

app = Flask(__name__)


@app.route('/download', methods=['GET'])
def download_pdf():
    env = Environment(loader=PackageLoader(current_app.name, 'templates'))
    template = env.get_template('test.html') # 获得页面模板

    html = template.render(
        name=u'大Ren', font_path=current_app.root_path + '/static/simsun.ttf').encode('utf-8')
    result = StringIO()
    pdf = pisa.CreatePDF(StringIO(html), result)
    resp = make_response(result.getvalue())
    resp.headers["Content-Disposition"] = ( 
        "attachment; filename='{0}'; filename*=UTF-8''{0}".format('test.pdf'))
    resp.headers['Content-Type'] = 'application/pdf'
    return resp

if __name__ == '__main__':
    app.run()

启动app之后,访问:

http://localhost:5000/download

即可生成下载。

本文来自网易实践者社区,经作者王一兵授权发布。