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.set_font('Arial','B',15)
       self.cell(65) # padding
       self.cell(60,10,response.title,1,0,'C')
       self.ln(20)

   def footer(self):
       self.set_y(-15)
       self.set_font('Arial','I',8)
       txt = 'Page %s of %s' % (self.page_no(), self.alias_nb_pages())
       self.cell(0,10,txt,0,0,'C')

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',
                                requires=IS_DATE(),
                          Field('end_date', 'date', 
                                label='End Date',
                                requires=IS_DATE()))
   #form with invisible fields for PDF requesting
   pdf_link = FORM(INPUT(_type='submit', _value='PDF'),
                 hidden=dict(start_date=request.vars.start_date,
                             end_date=request.vars.end_date),
                _action='report.pd')
   #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()
           pdf.add_page()
           #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
           pdf.write_html(t_rep.xml().decode('UTF-8').encode('cp1252'))
           response.headers['Content-Type'] = 'application/pdf'
           #send the PDF as a string
           return pdf.output(dest='S')
       else:
           #displays form for input, the report and a PDF button
          return dict(form=form, rep=rep, pdf_link=pdf_link)
   else:
       #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"}}
{{=rep}}
<hr>
{{if pdf_link:}}
    {{=pdf_link}}
{{pass}}
{{=rep}}

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