Helga
Helga

Reputation: 41

Footer only on last data page in Reportlab

I am working on an invoice and I would like to add a footer on the last page only (which can also be the first page).

Since the data of the table is dynamic, I am not able to calculate the number of pages.

Now I am working with 2 Page Templates, firstpage (with 2 frames and footer1) and nextpages (with 1 frame and footer2). This works when the data fills two pages, but when the table fills only 1 page or more then 2 pages, it no longer works.

I defined the footer in the following way:

    footerFrame = Frame(x1=35*mm, y1=20*mm, width=175*mm, height=15*mm)
    footerStory = [ Paragraph("Have a nice day.", styles["fancy"]) ]

    def footer2(canvas,document):
        canvas.saveState()
        footerFrame.addFromList(footerStory, canvas)
        canvas.restoreState()

Is there a more flexible way to define a footer, so it only shows up on the page at which the table ends?

Thanks in advance.

Upvotes: 3

Views: 1827

Answers (1)

J Carroll
J Carroll

Reputation: 1391

By overriding ReportLabs canvas Class, you CAN keep track of the pages (granted I've done it with other reports that don't involve flowables, but I believe you can still make it work!) .

Since you are using a flowable (Paragraph), you need to know how many pages it is going to be with each new PDF generation (the length is the dynamic part). I am not 100% positive, but I think ReportLab's flowable still invoke the "showPage()" method of the canvas. So you can do the following:

In pseudo-code/part-python, I'd recommend the following (untested):

class MyFooterCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        ## Subclass the ReportLab canvas class.  
        canvas.Canvas.__init__(self, *args, **kwargs)
        ## Create an empty list to store the saved pages so you can keep track of them.
        self._savedPages = []

    def showPage(self):
        """Override the showPage method"""

        ## We are writing our own showPage() method here, so we can keep track of 
        ## what page we are on.
        self._savedPages.append(self)
        ## Start a new page.
        self._startPage()

    def drawFooter(self):
        """Draws the footer to the page.  You can have it do whatever you want here"""
        self.drawString(50, 50, "This is my footer, yay me - footer freedom")

    def save(self):
        """Saves the entire PDF in one go, a bit costly to do it this way,
           but certainly one way to get a footer."""
        numPages = len(self._savedPages)

        for pages in self._savedPages:
            ## Finds the last page and when it 'hits', it will call the self.drawFooter() method.
            if pages == self._savedPages[-1]:
                self.drawFooter()
            else:
                ## If it's not the last page, explicitly pass over it.  Just being thorough here.
                pass

        ## And... continue doing whatever canvas.Canvas() normally does when it saves.
        canvas.Canvas.save(self)

AGAIN this is untested, but I think this will give you the behavior you want. Try it out, if you get stuck let me know, I can hash some of this out if need be, but I've done this same method for other non-flowables and it's worked for me in the past.

Upvotes: 4

Related Questions