【问题标题】:Split a table across more than 1 page in Reportlab在 Reportlab 中拆分超过 1 页的表格
【发布时间】:2014-04-03 05:49:17
【问题描述】:

我正在尝试将“全角”表格拆分为 2 页甚至更多页。我使用 ReportLab 的 Platypus 库和 BaseDocTemplate 类。

我有一个“全宽”元素表,它应该被绘制到第一页的框架中,如果表有足够的行它应该在第二页继续。我的问题是第一页的框架与其他框架的高度和位置不同,因为在第一页的顶部我需要显示更多信息(是的......我在谈论发票或订单)。

经过数千次尝试,我得到的只是一个 pdf,其唯一页面只有 8 个项目/行,这正是他们在第一页所需的空间,但如果表格超过 8 行,那么我得到一个只有 1 页且没有表格的 pdf(这意味着一个空框架,尽管我在日志中看到了所有数据)。

我使用了 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*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)

提前谢谢你!!

【问题讨论】:

    标签: python django pdf-generation reportlab


    【解决方案1】:

    您发布的代码缺少一些数据并且本身不能运行,所以我无法确定我的答案是否正确。如果这不起作用,请扩展您的代码!

    首先,您根本不必使用wrapsplit 方法!当doc.build 使用该故事时,该表将自行拆分。此外,split 不会拆分表内联,而是只返回一个表列表。因此,在您的情况下,splitter 是您对其进行迭代然后将 empty 列表附加到框架的表列表。我建议你跳过那部分。您正在将不同的元素添加到各个框架中。因此,您可以将拆分后的表添加到 dataframeX,但可能永远不会使用 dataframeX,因为您从未使用过 next_pages PageTemplate。为此,您必须在完成第一页后将NextPageTemplate() 添加到故事中。我会让 platypus 为您做这些事情:只需让您的方法返回带有生成元素的列表并将它们连接起来,然后再将它们传递给 doc.build()

    【讨论】:

    • 非常感谢您的回答!现在我可以看到我走错了路,你是对的,现在我可以看到,正如你所说,我在框架上附加了一个空列表。明天我会尝试优化这段代码。非常感谢!
    猜你喜欢
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多