Monday, November 12, 2012

How To Render Total Pagenumber In Pdf's With Reportlab

Here is my way to render pdf-files with a "totalPagenumber" option:

Note: The pdf is rendered twice. This may cause problems on low-performance machines or for very big files.

The idea is to pass the number of pages from the first rendering to the second.
To do this I use this function:

from pyPdf import PdfFileReader

def genPdf(renderPageNumber=True):
    filename = pdfWriter()
    if renderPageNumber:
        pdfFile = pdfFileReader(open(filename,'rb'))
        filename = pdfWriter(' / %d'%pdfFile.numPages)

To get the number of pages of a pdf file you need the pyPdf package!

The pdfWriter function generates the pdf file:

from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.rl_config import defaultPageSize
from reportlab.lib.units import inch

def pdfWriter( totalPages='' ):

    filename = 'test.pdf'
    PAGE_HEIGHT=defaultPageSize[1]
    PAGE_WIDTH=defaultPageSize[0]
    styles = getSampleStyleSheet()
    Title = "Hello world"
    pageinfo = "platypus example"

    def myFirstPage(canvas, doc):
        canvas.saveState()
        canvas.setFont('Times-Bold',16)
        canvas.drawCentredString(PAGE_WIDTH/2.0, PAGE_HEIGHT-108, Title)
        canvas.setFont('Times-Roman',9)
        canvas.drawString(inch, 0.75 * inch,"%s: Page %d%s" % (pageinfo, doc.page, totalPages) )
        canvas.restoreState()

    def myLaterPages(canvas, doc):
        canvas.saveState()
        canvas.setFont('Times-Roman', 9)
        canvas.drawString(inch, 0.75 * inch,"%s: Page %d%s" % (pageinfo, doc.page, totalPages) )
        canvas.restoreState()

    doc = SimpleDocTemplate(filename)
    Story = [Spacer(1,2*inch)]
    style = styles["Normal"]
    for i in range(100):
        bogustext = ("Paragraph number %s. " % i) *20
        p = Paragraph(bogustext, style)
        Story.append(p)
        Story.append(Spacer(1,0.2*inch))
    doc.build(Story, onFirstPage=myFirstPage, onLaterPages=myLaterPages)
    return filename

The pdf rendering is done by the ReportLab Toolkit.

To return the pdf as responce in a django app, I use a function like this, where i render the pdf into a cStringIO. The output I add to the response in the view.

Wednesday, November 7, 2012

Django Tips: How To Get Current Variables Or Request

When developing django-apps, I often raise a ZeroDivisionError to stop the script at a certain point.

print 1/0

This makes especially sense to debug code which includes save or redirect commands.

This is also an easy possibility to access the current local vars or request at a certain point of your script via the django traceback.

You have to enable debugging in your django settings:

DEBUG = True

Sunday, October 21, 2012

How To Setup Vertical Centered Labels With One Or Two Lines

The Problem

You try to style a form where you have labels with a fixed width. In some cases this leads to more than one line. You could define an individual style for each label. But this solution is very costly and it crashes if you need multilingual support because different languages may lead to different numbers of lines.

The Solution

There is an easy css-trick to get this behavior. You can set vertical-align: middle; in order to center the label. The vertical-align property requires the label to be wrapped into a div which is displayed as table. The label-tag itself has to be displayed as table-cell.

Example

CSS

.labelWrapper {
    display: table;
    float: left;
    height: 40px;
    line-height: 20px;
    margin: 3px 0; /*input border+padding*/
    width: 100px;
}

label {
    display: table-cell;
    vertical-align: middle;
}

input {
    height: 40px;
    padding: 2px 20px;
}

HTML

<form action="#" method="GET">
  <div class="fieldWrapper">
    <div class="labelWrapper">
      <label for="id_name">Name</label>
    </div>
    <input id="id_name" name="name" type="text">
  </div>
  <div class="fieldWrapper">
    <div class="labelWrapper">
      <label for="id_honorific_prefixes">Honorific Prefixes</label>
    </div>
    <input id="id_honorific_prefixes" name="honorific_prefixes" type="text">
  </div>
</form>