学习利用ReportLab生成PDF报表 -- 准备工作及Demo

  1. 官方Demo
    官网提供了一个demo,下载地址:
    http://www.reportlab.com/static/cms/files/RLtutorial.zip
    在运行前需要安装相关的依赖包。在ReportLab网站注册并登陆后会有更完整的文档。
  • rlextra: 安装该包前需要注册ReportLab用户,登陆后才能下载。
    pip install rlextra -i https://www.reportlab.com/pypi
    在下载完成rlextra后会自动下载其他依赖包。
  • preppy: 一种预处理程序,利用其来读取模板template。
    参考: https://bitbucket.org/rptlab/preppy
  • reportlab
  • pyRXP
  • 等等

安装完成相关包后执行文件夹下product_catalog.py,仍发现有很多错误,主要集中在编码,StringIO/BytesIO(Demo文件中是用了StringIO作为buf,但执行报错,查看相关源码文件后发现需要用BytesIO。)上,除此之外Demo中的数据是通过解析XML文件得到的,可能以后使用中不会使用XML来获取数据,所以决定自己重新写一个新的Demo。

  1. 自己编写的SimpleDemo
    简单的生成一份pdf报表主要需要三方面的准备:数据,模板文件(prep, rml),相关简单工具方法。编写模板文件和数据准备相比较更重要,更繁琐,而简单的编写工具方法比较轻松,不过后期肯定需要优化。
  • 数据: 从mongodb数据库中获取。
  • 模板文件: 利用RML(Report Markup Language)编写模板,可在其中嵌套Python代码,详细文档可登陆ReportLab后下载。下面是一个最基本的RML模板(取自官方RML2PDF with Django Demo):
<!DOCTYPE document SYSTEM "rml.dtd">
<document filename="hello.pdf">
    <template showBoundary="0">
        <pageTemplate id="main">
             <frame id="first" x1="50" y1="200" width="450" height="300"/>
        </pageTemplate>
    </template>
    <stylesheet>
        <paraStyle name="textstyle1" fontName="Helvetica" fontSize="24" leading="24" />
    </stylesheet>
    <story>
        <para style="textstyle1">
             Welcome<b>{{name}}<b>, to the world of RML!
        </para>
    </story>
</document>
  • 相关简单工具方法:
from rlextra.rml2pdf import rml2pdf
import preppy
from io import BytesIO
class PDFUtils(object):
        def __init__(self, template_name, namespace, output_filename=None):
            self.template_name = template_name
            self.namespace = namespace
            self.output_filename = output_filename
          
            # 其他相关操作(注册字体等)

        def create_pdf(self):
            source_text = open(self.template_name, 'r', encoding='utf-8').read()
            template = preppy.getModule(self.template_name, sourcetext=source_text)
            # template = preppy.getModule(self.template_name)
            rml = template.getOutput(self.namespace)

            if self.output_filename:
                rml2pdf.go(rml, outputFileName=self.output_filename)
                return True
            else:
                buf = BytesIO()
                rml2pdf.go(rml, outputFileName=buf)
                pdf_data = buf.getvalue()
                return pdf_data

需要注意的是,若要输出IO流(如web请求时下载pdf报表文件),这里用的是BytesIO。若像官方Demo中用StringIO,在执行rml2pdf.go()时会抛出TypeError: string argument expected, got 'bytes'异常,查看文件pdfdoc.py源码:

data = self.GetPDFData(canvas)
if isUnicode(data):
        data = data.encode('latin1')
f.write(data)

这里self.GetPDFData(canvas)返回的是bytes,在f.write()时需要BytesIO类型。(暂时不知道其他解决办法)
除此之外,在利用preppy.getModule()解析rml文件时,若rml文件中出现中文字符直接利用preppy.getModule(template_name)会出现gbk无法解析中文的情况,查看源码发现当只有一个name参数时,getModule()会默认open(name, 'r').read()出现UnicodeDecodeError。所以使用利用sourcetext参数,先按指定编码读取文件内容再解析,即

source_text = open(template_name, 'r', encoding='utf-8').read()
template = preppy.getModule(template_name, sourcetext=source_text)
```,同时需要在rml文件中注册中文字体。
 * main(): 

if name == 'main':
# 模板文件
template = 'hello.rml'
# 输出的pdf
output_filename = 'output/simple_demo.pdf'
# 数据
namespace = {
'name': 'JiangW'
}
p = PDFUtils(template, namespace, output_filename=output_filename)
p.create_pdf()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 在生成PDF报表时,往往需要动态的生成表格和一些折线图、饼状图等,利用RML文件和reportlab的api来动态...
    蒋狗阅读 2,976评论 1 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,156评论 19 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,806评论 18 399
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,993评论 6 342
  • 【天界传说】第一部 微互助,全民参与,操作易懂,小投资大收益, 拒绝假实体,拒绝黑客攻击 严谨控盘团队,公开透明,...
    大磊哥哥阅读 225评论 0 0