Django 生成PDF(二)

 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 <module>
    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文档为:

<?xml version="1.0" encoding="utf-8" standalone="no" ?> 
<!DOCTYPE document SYSTEM "rml.dtd"> 
<document filename="financial_products.pdf" compression='1'> 
{{script}}#coding=utf-8{{endscript}}
{{script}}import locale;locale.setlocale(locale.LC_ALL, '');{{endscript}}
<docinit>
	<color id="BLUE" CMYK="[1,0.67,0,0.23]"/>
</docinit>
<template pageSize="(595, 842)" leftMargin="72" rightMargin="72" >

	<pageTemplate id="head" pageSize="a4 portrait">
        <pageGraphics>
            <image file="{{STATIC_DIR}}/img/db_logo.jpg" x="50" y="780" width="302" height="53"/>
            <fill color="black"/>
            <setFont name="song" size="10"/>
			<lineMode width="2"/>
			<lines>
			40 765 555 765
			</lines>
			<fill color="#ADD8E6"/>
			<lineMode width="1" />
			<lines>
			0 60 595 60
			</lines>
			<fill color="#778899"/>
			<setFont name="song" size="10"/>
            <drawString x="235" y="40">客服热线:4006-816-886 </drawString>
			<drawString x="450" y="40">当前第<pageNumber countingFrom="1"/>页 / 总共4页</drawString>
        </pageGraphics>
		<frame id="second" x1="35" y1="85" width="525" height="660"/>
    </pageTemplate>
</template>

<stylesheet>
	<initialize>
		<alias id="style.normal" value="style.Normal"/>
	</initialize>
	<paraStyle name="common"  fontName="song" fontSize="12" leading="18" spaceBefore="6" spaceAfter="12" firstLineIndent="0.5in" />
	<paraStyle name="alignLeft" alignment="left" fontName="song" fontSize="12" leading="15" spaceBefore="6" spaceAfter="8" firstLineIndent="0.2in" />
	<paraStyle name="noIndent" alignment="left" fontName="song" fontSize="12" leading="15" spaceBefore="6" spaceAfter="8" />
	<paraStyle name="alignRight" alignment="right"  fontName="song" fontSize="12" leading="15" spaceBefore="6" spaceAfter="12" firstLineIndent="0.5in" />
	<paraStyle name="title" fontName="song" fontSize="30" leading="24" spaceBefore="6" spaceAfter="50" alignment="center"/>
	<paraStyle name="paddingLeft" alignment="left" fontName="song" fontSize="12" leading="15" spaceBefore="6" spaceAfter="8" firstLineIndent="250" />
</stylesheet>

<story>
<setNextTemplate name="head"/>
<para style='title'><b>标题</b></para>
<para style="alignRight">备案号:<b>{{data.get_record_num()}}</b></para>
<para style="noIndent"><b>甲方:</b></para>
<para style="noIndent">姓名:{{data.owner.userprofile.realname and data.owner.userprofile.realname.encode('utf-8') or data.owner.userprofile.nickname.encode('utf-8')}}</para>
<para style="noIndent">
  证件名称:{{data.owner.userprofile.id_type and data.owner.userprofile.id_type.encode('utf-8') or ''}} , 证件号码:{{data.owner.userprofile.id_no}}
</para>
<para style="noIndent"></para>
<para style="noIndent"><b>乙方:</b></para>
<para style="noIndent">某某某公司</para>
<para style="noIndent"></para>
<para style="alignLeft">本协议为甲方与乙方之间的产品服务合同,双方在签署上述产品合约前,已认真阅读及同意接受合约条款。本合同系双方经平等自愿协商一致,根据《中华人民共和国合同法》等法律、行政法规的规定订立。</para>
<para style="noIndent"></para>
<para style="alignLeft"><b><u>1. 定义与说明</u></b></para>
<para style="alignLeft"><b>1.1</b> 乙方接受甲方的委托和授权,按照与甲方事先约定的投资计划和方式进行投资和资产管理,根据约定条件和实际投资收益情况向甲方支付收益并按约定条件和比例收取管理服务费,投资风险由甲方自行承担。</para>
<para style="alignLeft"><b>1.2</b> 在本合同中,除非另有明确说明,否则下列词语具有如下含义:</para>
<para style="alignLeft"><b>账户:</b>指乙方为甲方开立的贷帮网账户。</para>
<para style="alignLeft">
  <b>起息日:</b>指投资收益计算的起始日,即产品合约中约定的起息日。</para>
<para style="alignLeft">
  <b>到期日:</b>指产品合约中约定的到期日。</para>
<para style="alignLeft">
  <b>期限:</b>指起息日至到期日或(提前终止日)之间的期限。</para>
<para style="alignLeft">
  <b>收益:</b>指甲方投资本金在产品期限内产生的收益。</para>
<para style="alignLeft">
  <b>支付周期:</b>指乙方在甲方提出赎回申请后完成支付所需时间。</para>
<para style="alignLeft">
  <b>工作日:</b>指乙方对外办理一般业务的任何一天,不包括法定节假日和周六、周日(但包括国家临时规定应当工作的周六或周日)。</para>
<para style="alignLeft">
  <b>推介期:</b>指乙方计划完成推广本产品所需时间段。 </para>
<para style="alignLeft">
  <b>封闭期:</b>指乙方受甲方委托完成投资所需的时间段。</para>
<para style="alignLeft">
  <b>签约日:</b>指双方签署的产品合约中列明的签约日期。</para>

<para style="noIndent"></para>
<para style="alignLeft"><b><u>2. 声明与保证</u></b></para>
<para style="alignLeft">
  <b>2.1</b> 双方均分别向另一方声明并保证该方具有完全适当的资格与能力订立、接收及履行本合同以及以其为一方的其他任何有关文件。</para>
<para style="noIndent"></para>
<para style="noIndent"></para>
<para style="noIndent"></para>
<para style="paddingLeft">某某公司</para>
<para style="noIndent">甲方签字:<u>{{data.owner.userprofile.realname and data.owner.userprofile.realname.encode('utf-8') or data.owner.userprofile.nickname.encode('utf-8')}}</u>
</para>
<para style="paddingLeft">经办人(加盖个人名章或签字):</para>
<image file="{{STATIC_DIR}}/img/common/cachet.gif" x="350" y="350" width="168" height="168"/>
</story>
</document>


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'

更多详情请参见下文。


评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值