文档章节

Django使用reportlab套件生成PDF文件

alazyer
 alazyer
发布于 2018/04/20 13:39
字数 821
阅读 4.6K
收藏 1

行业解决方案、产品招募中!想赚钱就来传!>>>

简介

项目中生成了一个实例,需要提供给用户下载pdf文件功能。

最开始想到的是使用前段技术,直接将html页面保存为pdf文件。这个过程使用了html2pdf,这个纯js项目。该项目会将指定的DOM元素通过html2canvas工具保存为图片,然后通过jsPDF工具将保存的图片最终以pdf文件形式展现,并直接供下载。

这样做有个缺点就是当页面非常长时,就有可能出现一行文字被从中间截断,展示在两页pdf文件中的情况。因而需要寻找更高级,输出格式更优雅的解决方案。最后发现了可以通过Reportlab套件来完成工作。

工作流

要想通过Reportlab套件来生成pdf文件的工作流程主要分三步:

  1. django后台通过与数据库或者其他调用获取数据
  2. 将这些数据传入到RML(Report Markable Language)模板,并调用reportlab套件生成二进制数据
  3. django根据生成的数据返回响应

第1和第3步可以参考官方outputting pdf文档

比较关键的是第2步如何实现,下面将针对RML、以及如何调用reportlab套件生成二进制数据进行详细讲解

RML和Reportlab套件使用

关于RML可以参考Reportlab提供的RML-for-IdiotsRML User Guide两个文档进行学习,这里并不赘述。只介绍个人使用的一些体会。

  • 首页与其余页使用不同模板

要想实现第一页和后面其余页使用不同的模板,在<story>上添加firstPageTemplate属性,指定第一页的模板。紧接着使用<setNextTempate name='main'>来指定剩余页(如果有的话)使用的模板。

如果想整个pdf使用同一个模板的话,则无须使用<setNextTempate name='main'>

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<!DOCTYPE document SYSTEM "rml_1_0.dtd"> 
<document filename="rml.pdf">

<template pagesize="(595, 842)" leftMargin="72">
    <pageTemplate id="head">
        <pageGraphics>
            <setFont name="bighei" size="24"/>
            <drawCentredString x="297.5" y="760">{{ name }}</drawCentredString>
        </pageGraphics>
        <frame id="first" x1="80" y1="80" width="435" height="550"/>
	</pageTemplate>
	<pageTemplate id="main">
        <frame id="first" x1="80" y1="80" width="435" height="682"/>
	</pageTemplate>
</template>

<stylesheet>
	<initialize>
	<alias id="style.normal" value="style.Normal"/>
	</initialize>

	<paraStyle name="chapter title"    fontName="bighei" fontSize="20" leading="36"                  spaceAfter="10"/>

	<paraStyle name="question stem"    fontName="bighei" fontSize="12" leading="12" spaceBefore="15" spaceAfter="10"/>

	<paraStyle name="question options" fontName="bighei" fontSize="10" leading="12"                  spaceAfter="5" />
</stylesheet>

<story firstPageTemplate="head">

    <setNextTemplate name="main" />
    {{ paras }}

</story>

</document>
  • 通过Django template解决RML不能嵌套循环问题

个人在使用过程中发现无法在RML模板中进行嵌套循环,

{{ for outter_item in outter_list }}
    {{ for inner_item in outter_item }}
    {{ innger_item }}
    {{ endfor }}
{{ endfor }}

但是Django模板中并无此限制,因而可以直接调用render_to_string方法将RML需要的字符串使用django的机制来生成,然后再传给RML解决这个问题。

from io import BytesIO
import preppy
import trml2pdf

TEMPLATE = os.path.join(PATH_TO_TEMPLATE_DIR, 'template.prep')
def generate_pdf():

    django_context = dict()

    paras = render_to_string('django_templates.html', django_context)

    rml_context = dict(
        name='RML Test',
        paras=paras.encode("utf-8")
    )

    template = preppy.getModule(template_path)
    rml = template.getOutput(rml_context)

    return trml2pdf.parseString(rml)
  • 解决中文乱码问题

RML默认不支持中文,需要自己注册支持中文的字体

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase import ttfonts

pdfmetrics.registerFont(ttfonts.TTFont(font_name, font_path))
  • Django views
def test_rml(request):
    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="rml.pdf"'
    
    pdf = generate_pdf()
    
    response.write(pdf)
    
    return response
alazyer
粉丝 5
博文 68
码字总数 35105
作品 0
程序员
私信 提问
加载中
请先登录后再评论。
浅入浅出Android(003):使用TextView类构造文本控件

基础: TextView是无法供编辑的。 当我们新建一个项目MyTextView时候,默认的布局(/res/layout/activity_main.xml)中已经有了一个TextView: <TextView 运行效果如下: 修改其文本内容...

樂天
2014/03/22
619
1
CDH5: 使用parcels配置lzo

一、Parcel 部署步骤 1 下载: 首先需要下载 Parcel。下载完成后,Parcel 将驻留在 Cloudera Manager 主机的本地目录中。 2 分配: Parcel 下载后,将分配到群集中的所有主机上并解压缩。 3 激...

cloud-coder
2014/07/01
6.8K
1
beego API开发以及自动化文档

beego API开发以及自动化文档 beego1.3版本已经在上个星期发布了,但是还是有很多人不了解如何来进行开发,也是在一步一步的测试中开发,期间QQ群里面很多人都问我如何开发,我的业余时间实在...

astaxie
2014/06/25
2.7W
22
5分钟 maven3 快速入门指南

前提条件 你首先需要了解如何在电脑上安装软件。如果你不知道如何做到这一点,请询问你办公室,学校里的人,或花钱找人来解释这个给你。 不建议给Maven的服务邮箱来发邮件寻求支持。 安装Mav...

fanl1982
2014/01/23
1.2W
6
代码生成器--Codgen

Codgen是一个基于数据库元数据模型,使用freemarker模板引擎来构建输出的代码生成器。freemarker的数据模型结构通常来说都是一个Map树状结构模型,codgen也不例外,它的数据模型这棵树的根节...

黄天政
2013/01/29
1.4W
2

没有更多内容

加载失败,请刷新页面

加载更多

重拾Java反射(为什么?)

前言:如标题所述,为什么要重拾Java反射?究其缘由,在Java中反射具有举足轻重的地位,一直以来都是Java中的闪亮点,并且反射是一系列出众的web框架设计的灵魂所在。PS:本文主要是理论,篇...

Umizhang
2019/06/07
0
0
删除文本文件中包含特定字符串的行 - Delete lines in a text file that contain a specific string

问题: 我将如何使用sed删除文本文件中包含特定字符串的所有行? 解决方案: 参考一: https://stackoom.com/question/MhaH/删除文本文件中包含特定字符串的行 参考二: https://oldbug.net...

富含淀粉
3分钟前
0
0
巧用 Matplotlib 动画,让你的 Python 可视化大放异彩

— 1 — 前言 如果你对本文的代码感兴趣,可以去 Github (文末提供)里查看。第一次运行的时候会报一个错误(还没找到解决办法),不过只要再运行一次就正常了。 这篇文章虽然不是篇典型的数...

Python大数据分析
05/19
0
0
如何追班花?贝叶斯公式来帮忙

0 1 条件概率 在某个美丽的校园里,小扎喜欢上了班花小美,暗恋了很久终于想鼓起勇气追小美。 但是小扎知道自己长得不帅,不是富二代,成绩也不是很好,追小美这件事,小扎在心里估算了下,成...

zhanyd
01/12
0
0
Docker中级篇|深入探究Docker

简介: 深入探究Docker Docker镜像理解 Docker镜像是什么 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代...

一肥仔
4分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部