在Reportlab中跨多个页面分割表格 [英] Split a table across more than 1 page in Reportlab

查看:241
本文介绍了在Reportlab中跨多个页面分割表格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将全角表分割为2页或更多。我使用ReportLab的Platypus库和BaseDocTemplate类。



我有一个全宽的元素表,这应该被绘制到第一页的框架,如果表有足够的行应该继续在第二页。我的问题是,第一页的框架与其他页面的高度和位置不同,因为在第一页的顶部,我需要显示更多信息(是...我在谈论发票或订单)。在数千次尝试之后,所有这些都是一个pdf,只有8个项目/行的唯一页面,这正是他们在第一页需要的空间,但是如果表格超过8行,那么我得到一个只有1页的表格,没有表格(这意味着一个空框架,尽管我看到日志中的所有数据)。



我使用了方法split()和wrap(),但可能是错误的方式,因为我是新的ReportLab。我向您显示我的代码的最后一个版本:

  from django.http import HttpResponse 
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.platypus import BaseDocTemplate,PageTemplate,Table,Spacer ,Frame,TableStyle,\
NextPageTemplate,PageBreak,FrameBreak

PAGE_WIDTH = A4 [0]
PAGE_HEIGHT = A4 [1]
MARGIN = 10 * b
$ b class ThingPDF(BaseDocTemplate):
def header(self,canvas,subheader = True):
#print'header()'
data = [('AAAA ','Thing%s'%(self.thing.name))]]

s = []
t = Table(data,colWidths = [95 * mm,95 * rowHeights = None,style = None,splitByRow = 1,
repeatRows = 0,repeatCols = 0)
t.setStyle(TableStyle([
('BACKGROUND',(0,0) (0, 0),colors.red),
('BACKGROUND',(1,0),(1,0),colors.blue),
('ALIGN',(1,0) 1,0),'RIGHT'),
]))
s.append(t)

#如果子标题:
#print'subheader'

self.head.addFromList(s,canvas)


def data_table(self,canvas,items):
#print'data_table()'
d =项目中的项目

$ [$ u $ $' b d.append([item.col0,item.col1,item.col2,item.col3,item.col4])

s = []
t = Table(d,colWidths = [ 20 * mm,100 * mm,20 * mm,20 * mm,30 * mm],rowHeights = 20 * mm,style = None,\
splitByRow = 1,repeatRows = 0,repeatCols = 0)

t.setStyle([('BACKGROUND',(0,0),(-1,0),('#eeeeee'))])


h = 187 * mm #TODO
w = A4 [0] - (2 * MARGIN)

splitter = t.split(w,h)
#print'\\\
\\\
result of split:',len(splitter)

for i in splitter:
print'i:',i
self.dataframeX.addFromList(s,canvas)

s.append(t)
self.dataframe0.addFromList(s,画布)

def on_first_page(self,canvas,doc):
canvas.saveState()
self.header(canvas)
self.data_table(canvas,self
canvas.restoreState()

def on_next_pages(self,canvas,doc):
canvas.saveState()
self.header(canvas,subheader = False)
canvas.restoreState()

def build_pdf(self,thing = None,items = None,user = None):
self.thing = thing
self.items = items

self.doc = BaseDocTemplate('%s.pdf'%(thing.name),
pagesize = A4,
pa geTemplates = [self.first_page,self.next_pages,],
showBoundary = 1,
rightMargin = MARGIN,
leftMargin = MARGIN,
bottomMargin = MARGIN,
topMargin = MARGIN,
allowSplitting = 1,
title ='%s'%'title')

self.story.append(Spacer(0 * mm,2 * mm) )
self.doc.build(self.story)

response = HttpResponse(mimetype ='application / pdf')
response ['Content-Disposition'] ='attachment ; filename =%s.pdf'%(reference)

return response

def __init __(self):
self.thing = None
self。 items = None
self.story = []

#==========框架==========
self.head =框架(x1 = MARGIN,y1 = A4 [1] - (2 * MARGIN),width = A4 [0] - (2 * MARGIN),height = 10 * mm,
leftPadding = 0,bottomPadding = 0 ,rightPadding = 0,topPadding = 0,id ='header',
showBoundary = 1)#,overlapAttachedSpace = None,_debug = None)
self.dataframe0 =框架(x1 = MARGIN,y1 = 10 * mm,width = A4 [0] - (2 * MARGIN),height = 187 * mm,
leftPadding = 0,bottomPadding = 0,rightPadding = 0,topPadding = 0,
id ='body ',showBoundary = 1)
self.dataframeX = Frame(x1 = MARGIN,y1 = MARGIN,width = A4 [0] - (2 * MARGIN),height = 257 * mm,
leftPadding = 0 ,bottomPadding = 0,rightPadding = 0,topPad ding = 0,
id ='body',showBoundary = 1)

#========== PAGES ==========
self.first_page = PageTemplate(id ='firstpage',frames = [self.head,self.dataframe0],onPage = self.on_first_page)
self.next_pages = PageTemplate(id ='nextpages',frames = [self.head,self.dataframeX],onPage = self.on_next_pages

提前谢谢!

解决方案

您发布的代码缺少一些数据,本身不可运行,所以我无法真正地告诉我的答案是正确的。如果这不行,请扩展你的代码!



首先,你不必使用 wrap split 方法!当 doc.build 消耗故事时,该表将分裂。而且,split不会拆分表内嵌,而只返回表的列表。所以在你的情况下, splitter 是一个表的列表,您可以在其中迭代,然后将列表附加到框架中。我建议你跳过那一部分。您将不同的元素添加到单个框架。因此,您可以将分割表添加到dataframeX,但是dataframeX可能永远不会被使用,因为您从不使用 next_pages PageTemplate 。为此,您必须在完成第一页之后添加一个 NextPageTemplate()到故事。我会让platypus为你做这些东西:只需让你的方法返回列表和生成的元素,并将它们连接起来,然后再传递给 doc.build()


I'm trying to split a "full-width" table across 2 pages or even more. I use the Platypus library of ReportLab and the BaseDocTemplate class.

I've a "full width" table of elements and this should be drawn into a frame of the first page, if the table has enough rows It should be continued in the second page. My problem is that the frame of the first page has a different height and position than the others, because at the top of the first page I need to show more information (Yes... I'm talking about an invoice or order).

After thousands attempts, all that I've got is a pdf with a unique page with only 8 items/rows, It's exactly the space that they require at the first page, but if the table has more than 8 rows, then I get a pdf with only 1 page and without the table (that means an empty frame, although I see all data in the log).

I've used the methods split() and wrap() but probably in the wrong way, because I'm new with ReportLab. I show you the last version of my code:

from django.http import HttpResponse
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.platypus import BaseDocTemplate, PageTemplate, Table, Spacer, Frame, TableStyle,\
                               NextPageTemplate, PageBreak, FrameBreak

PAGE_WIDTH = A4[0]
PAGE_HEIGHT = A4[1]
MARGIN = 10*mm

class ThingPDF(BaseDocTemplate):
    def header(self, canvas, subheader=True):
        # print 'header()'
        data = [('AAAA', 'Thing %s' % (self.thing.name)), ]

        s = []
        t = Table(data, colWidths=[95 * mm, 95 * mm], rowHeights=None, style=None, splitByRow=1,
                  repeatRows=0, repeatCols=0)
        t.setStyle(TableStyle([
                   ('BACKGROUND', (0, 0), (0, 0), colors.red),
                   ('BACKGROUND', (1, 0), (1, 0), colors.blue),
                   ('ALIGN', (1, 0), (1, 0), 'RIGHT'),
        ]))
        s.append(t)

        # if subheader:
        #     print 'subheader'

        self.head.addFromList(s, canvas)


    def data_table(self, canvas, items):
        # print 'data_table()'
        d = [[u'col0', u'col1', u'col2', u'col3', u'col4', ],]

        for item in items:
            d.append([item.col0, item.col1, item.col2, item.col3, item.col4])

        s = []
        t = Table(d, colWidths=[20*mm, 100*mm, 20*mm, 20*mm, 30*mm], rowHeights=20*mm, style=None,\
                  splitByRow=1, repeatRows=0, repeatCols=0)

        t.setStyle([('BACKGROUND', (0,0), (-1,0), ('#eeeeee'))])


        h=187*mm #TODO
        w=A4[0] - (2*MARGIN)

        splitter = t.split(w, h)
        # print '\n\nresult of splitting: ', len(splitter)

        for i in splitter:
            print 'i: ', i
            self.dataframeX.addFromList(s, canvas)

        s.append(t)
        self.dataframe0.addFromList(s, canvas)

    def on_first_page(self, canvas, doc):
        canvas.saveState()
        self.header(canvas)
        self.data_table(canvas, self.items)
        canvas.restoreState()

    def on_next_pages(self, canvas, doc):
        canvas.saveState()
        self.header(canvas, subheader=False)
        canvas.restoreState()

    def build_pdf(self, thing=None, items=None, user=None):
        self.thing = thing
        self.items = items

        self.doc = BaseDocTemplate('%s.pdf' % (thing.name),
                                pagesize=A4,
                                pageTemplates=[self.first_page, self.next_pages,],
                                showBoundary=1,
                                rightMargin=MARGIN,
                                leftMargin=MARGIN,
                                bottomMargin=MARGIN,
                                topMargin=MARGIN,
                                allowSplitting=1,
                                title='%s' % 'title')

        self.story.append(Spacer(0*mm, 2*mm))
        self.doc.build(self.story)

        response = HttpResponse(mimetype='application/pdf')
        response['Content-Disposition'] = 'attachment; filename=%s.pdf' % (reference)

        return response

    def __init__(self):
        self.thing = None
        self.items = None
        self.story = []

        #==========  FRAMES  ==========
        self.head = Frame(x1=MARGIN, y1=A4[1] - (2*MARGIN), width=A4[0] - (2*MARGIN), height=10*mm,
                       leftPadding=0, bottomPadding=0, rightPadding=0, topPadding=0, id='header',
                       showBoundary=1)#, overlapAttachedSpace=None, _debug=None)
        self.dataframe0 = Frame(x1=MARGIN, y1=10*mm, width=A4[0] - (2*MARGIN), height=187*mm,
                                leftPadding=0, bottomPadding=0, rightPadding=0, topPadding=0,
                                id='body', showBoundary=1)
        self.dataframeX = Frame(x1=MARGIN, y1=MARGIN, width=A4[0] - (2*MARGIN), height=257*mm,
                                leftPadding=0, bottomPadding=0, rightPadding=0, topPadding=0,
                                id='body', showBoundary=1)

        #==========  PAGES  ==========
        self.first_page = PageTemplate(id='firstpage', frames=[self.head, self.dataframe0], onPage=self.on_first_page)
        self.next_pages = PageTemplate(id='nextpages', frames=[self.head, self.dataframeX], onPage=self.on_next_pages)

Thank you in advance!!

解决方案

The code that you posted is lacking some data and is not by itself runnable, so i can't really tell if my answer will be correct. Please extend your code if this doesn't work!

First of all, you don't have to use the wrap and split methods at all! The table will split itself when doc.build consumes the story. Also, split doesn't split the table inline, but returns just a list of tables. So in your case splitter is a list of tables over which you iterate and then append an empty list to the frame. I would suggest that you skip that part. You are adding the different elements to individual frames. Because of this, you would add the splitted table to the dataframeX but dataframeX might never be used, because you are never using the next_pages PageTemplate. For this you have to add an NextPageTemplate() to the story, after you are finished with your first page. I would let platypus do that stuff for you: Just let your methods return lists with the generated elements and concatenate them before passing them to doc.build().

这篇关于在Reportlab中跨多个页面分割表格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆