If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!

I found it good to put report classes in a separate file in models. So create a reports.py in models with this:

class Report(FPDF, HTMLMixin):

   def header(self):
       self.cell(65) # padding

   def footer(self):
       txt = 'Page %s of %s' % (self.page_no(), self.alias_nb_pages())

Note: this was taken and adpate from here

You will need a controller to make the form, do the query and render the PDF:

 def report():
   #form for the dates input
   form = SQLFORM.factory(Field('start_date', 'date', 
                                label='Start Date',
                          Field('end_date', 'date', 
                                label='End Date',
   #form with invisible fields for PDF requesting
   pdf_link = FORM(INPUT(_type='submit', _value='PDF'),
   #to do the query only one time
   #ask about extension for pdf or valid form data
   if request.extension == 'pd' or form.accepts(request.vars, session):
       #get date objects
       start_date = request.now.strptime(request.vars.data_ini, '%Y-%m-%d')
       end_date = request.now.strptime(request.vars.data_fim, '%Y-%m-%d')
       #the query
       rep = db((db.table.data >= data_ini) & 
                  (db.table.data <= data_fim)).select()
       #html table with the rows and labels from the models
       t_rep = SQLTABLE(rep, headers=dict([('table.' + f, db.table[f].label) for
                                            f in db.table.fields]))
       #if a pdf was requested
       if request.extension == 'pd':
           pdf = Report()
           #PYFPDF needs width attributs
           #as SQLTABLE don´t do like this, we need a hack
           ths = t_rep.elements('th')
           ths[0]['_width'] = '12%' # column widths
           ths[1]['_width'] = '60%'
           #send html to the pdf with required encoding
           response.headers['Content-Type'] = 'application/pdf'
           #send the PDF as a string
           return pdf.output(dest='S')
           #displays form for input, the report and a PDF button
          return dict(form=form, rep=rep, pdf_link=pdf_link)
       #display only the form and a message for input
      return dict(form=form, rep='Pick a date range.', pdf_link=None)

Note: Maybe there´s a better logic to achieve this.

And sure we need a view:

{{extend "layout.html"}}
{{if pdf_link:}}

That´s it! Maybe the oddest thing here is I coudn´t use a .pdf extension. This problem seems to appera when you have a non-generic view for the action.

Related slices

Comments (1)

Hosting graciously provided by:
Python Anywhere