Django 生成PDF(二)
接上文,我们本次使用RML来实现对PDF的生成与保存。
关于reportlab的详细信息,请戳以下链接:http://www.reportlab.com/software/opensource/。
本人用reportlab生成PDF的详细流程如下:
第一步,下载安装reportlab。这一步我就不赘述了。第二步,实现Demo。值得高兴的是,它提供了一个在线的Demo,http://www.reportlab.com/static/cms/files/RLtutorial.zip ,不过很遗憾,下载下来后不能用,报如下错误:
>>python product_catalog.py
Traceback (most recent call last):
File "product_catalog.py", line 5, in
import pyRXPU
ImportError: No module named pyRXPU
折腾了很久,还是没整成功,后来从其官方文档中得知:reportlab依赖于“preppy”、“pyrxp”、“rml2pdf”,而在新版本中reportlab已经将“preppy”、“pyrxp”、“rml2pdf”分拆出来,所以Demo中原来封装在“rlextra”中的包已经被分拆了。找了好久,从各个角落找到了相关包,如果需要的可以戳下面的链接进行下载:
(1)reportlab-preppy :
资源地址:http://download.csdn.net/detail/yima1006/6433059
文档地址:http://download.csdn.net/detail/yima1006/6433087
(2)reportlab-pyrxp:
资源地址:http://download.csdn.net/detail/yima1006/6433065
(3)trml2pdf:
资源地址:http://download.csdn.net/detail/yima1006/6433071
文档地址:http://download.csdn.net/detail/yima1006/6433095
(4)reportlab:
文档地址:http://download.csdn.net/detail/yima1006/6433077
在实际使用中,需要要装以上包,不过在生成中文文档时,需要自己注册中文字体,LZ在RML中注册中文字体始终没有解决,于是在工具类中手动注册成功。(备注:LZ用的字体是宋体,直接在windows字体文件炸中复制即可)。
RML文档为:
{{script}}#coding=utf-8{{endscript}}
{{script}}import locale;locale.setlocale(locale.LC_ALL, '');{{endscript}}
40 765 555 765
0 60 595 60
客服热线:4006-816-886
当前第 页 / 总共4页
标题
备案号:{{data.get_record_num()}}
甲方:
姓名:{{data.owner.userprofile.realname and data.owner.userprofile.realname.encode('utf-8') or data.owner.userprofile.nickname.encode('utf-8')}}
证件名称:{{data.owner.userprofile.id_type and data.owner.userprofile.id_type.encode('utf-8') or ''}} , 证件号码:{{data.owner.userprofile.id_no}}
乙方:
某某某公司
本协议为甲方与乙方之间的产品服务合同,双方在签署上述产品合约前,已认真阅读及同意接受合约条款。本合同系双方经平等自愿协商一致,根据《中华人民共和国合同法》等法律、行政法规的规定订立。
1. 定义与说明
1.1 乙方接受甲方的委托和授权,按照与甲方事先约定的投资计划和方式进行投资和资产管理,根据约定条件和实际投资收益情况向甲方支付收益并按约定条件和比例收取管理服务费,投资风险由甲方自行承担。
1.2 在本合同中,除非另有明确说明,否则下列词语具有如下含义:
账户:指乙方为甲方开立的贷帮网账户。
起息日:指投资收益计算的起始日,即产品合约中约定的起息日。
到期日:指产品合约中约定的到期日。
期限:指起息日至到期日或(提前终止日)之间的期限。
收益:指甲方投资本金在产品期限内产生的收益。
支付周期:指乙方在甲方提出赎回申请后完成支付所需时间。
工作日:指乙方对外办理一般业务的任何一天,不包括法定节假日和周六、周日(但包括国家临时规定应当工作的周六或周日)。
推介期:指乙方计划完成推广本产品所需时间段。
封闭期:指乙方受甲方委托完成投资所需的时间段。
签约日:指双方签署的产品合约中列明的签约日期。
2. 声明与保证
2.1 双方均分别向另一方声明并保证该方具有完全适当的资格与能力订立、接收及履行本合同以及以其为一方的其他任何有关文件。
某某公司
甲方签字:{{data.owner.userprofile.realname and data.owner.userprofile.realname.encode('utf-8') or data.owner.userprofile.nickname.encode('utf-8')}}
经办人(加盖个人名章或签字):
Python工具类:
#!/usr/bin/python
# -*- coding: utf-8 -*-
__author__ = '喵喵'
import os
import preppy
import logging
import traceback
import trml2pdf
from django.conf import settings
import reportlab.lib.styles
from reportlab.pdfbase import pdfmetrics, ttfonts
from reportlab.lib.fonts import addMapping
operation_logger = logging.getLogger('operation')
bug_log = logging.getLogger('bug')
class PDFUtils(object):
""" PDF 生成工具类
将一个标准的RML文件正常解析为PDF文件,保存并返回。具体参数如下"""
def __init__(self, font_dir=os.path.join(settings.HERE, 'utils', 'pdf', 'fonts'),
static_dir='http://%s/static' % settings.HOST_NAME):
""" 构造方法
@param font_dir 需要注册的字体文件目录
@param static_dir 静态文件地址目录
"""
super(PDFUtils, self).__init__()
self.STATIC_DIR = static_dir
try:
# 注册宋体字体
pdfmetrics.registerFont(ttfonts.TTFont('song', os.path.join(font_dir, 'STSONG.TTF')))
# 注册宋体粗体字体
pdfmetrics.registerFont(ttfonts.TTFont('song_b', os.path.join(font_dir, 'STZHONGS.TTF')))
except:
bug_log.error(traceback.format_exc())
addMapping('song', 0, 0, 'song') # normal
addMapping('song', 0, 1, 'song') # italic
addMapping('song', 1, 1, 'song_b') # bold, italic
addMapping('song', 1, 0, 'song_b') # bold
# 设置自动换行
reportlab.lib.styles.ParagraphStyle.defaults['wordWrap'] = "CJK"
def create_pdf(self, data, templ, save_file):
"""从二进制流中创建PDF并返回
@param data 渲染XML的数据字典
@param templ 需要渲染的XML文件地址(全路径)
@param save_file PDF文件保存的地址(全路径)
"""
# 读取模板文件
template = preppy.getModule(templ)
# 渲染模板文件
namespace = {
'data': data,
'STATIC_DIR': self.STATIC_DIR,
}
# 渲染PDF页面
rml = template.getOutput(namespace)
# 生成PDF
pdf = trml2pdf.parseString(rml)
# 保存PDF
open(save_file,'wb').write(pdf)
return True
if __name__ == '__main__':
pu = PDFUtils()
# 模板页面地址
temp_path = os.path.join(settings.HERE, 'templates', 'pact', 'products.prep')
for c in cerfts:
pdf_path = os.path.join(settings.HERE, 'medias', 'pdf_pact', 'product.pdf')
# 如果PDF不存在则重新生成
if not os.path.exists(pdf_path):
pu.create_pdf(c, temp_path, pdf_path)
print 'done'