Вопрос

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().

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top