Attention, cet article est technique… Si vous ne vous intéressez pas au développement en python, passez à l’article suivant :)

Vous voulez faire des rapports en pdf, envoyer des lettres ou une quelquonque autre action nécéssitant de la génération de PDF ?

Si vous êtes aguéris du monde python vous avez surement entendu parler de ReportLab.
Oui, mais l’ennui c’est que pour faire du reportlab, il faut faire du développementur et dur. Et lorsque l’on change sa template, il faut tout faire.

La solution, c’est RML, language xml permettant de génerer des pdf avec des feuilles de styles, en séparant en partie le contenu et le contenant (dans différentes parties du xml) fait par la société éditrice de reportlab.

Le hic ? le parseur de ce language est sous license propriétaire…
Heuresement, l’équipe de Z3C a fait z3c.rml, une implémentation libre de ce language.

Maintenant, on peut faire du RML à la main, mais pour générer des fichiers rml avec vos données, c’est plus dur. Les languages de templates me direz vous ? Oui, justement.

Votre serviteur a fait une librairie permettant d’automatiser ca en utilisant des templates genshi (language de templating xml particulièrement adapté à la tache), dans une classe gérant le tout.

Autre problème : reportlab monte en mémoire lorsque l’on a des pages chargées ou beaucoup de pages tout simplement.
Solution : pyjon.reports vous permet d’ajouter des sections petit à petit à votre document, et à la fin de générer un seul pdf avec toutes les sections (grâce à pypdf).

Pour les plus pressés, rendez-vous directement sur les exemples.

Cas concret : une table de données

D’abord initialisons une factory (classe permettant de rendre plusieurs documents en un) :

from pyjon.reports import ReportFactory
factory = ReportFactory()

Maintenant créons un fichier test.xml contenant notre template xml :

<?xml version="1.0" encoding="iso-8859-1" standalone="no" ?>
<!DOCTYPE document SYSTEM "rml_1_0.dtd">
<document xmlns:py="http://genshi.edgewall.org/">
<template pageSize="(595, 842)" leftMargin="72" showBoundary="0">
  <pageTemplate id="main">
    <frame id="first" x1="1in" y1="1in" width="6.27in" height="9.69in"/>
  </pageTemplate>
</template>
<stylesheet>
  <blockTableStyle id="mynicetable" spaceBefore="12">
    <lineStyle kind="OUTLINE" colorName="black" thickness="0.5"/>
    <blockFont name="Times-Bold" size="6" leading="7" start="0,0" stop="-1,0"/>
    <blockBottomPadding length="1"/>
    <blockBackground colorName="0xD0D0D0" start="0,0" stop="-1,0"/>
    <lineStyle kind="LINEBELOW" colorName="black" start="0,0" stop="-1,0" thickness="0.5"/>
    <!--body section-->
    <blockFont name="Times-Roman" size="6" leading="7" start="0,1" stop="-1,-1"/>
    <blockTopPadding length="1" start="0,1" stop="-1,-1"/>
    <blockBackground colorsByRow="0xD0FFD0;None" start="0,1" stop="-1,-1"/>
    <blockAlignment value="right" start="1,1" stop="-1,-1"/>

    <!-- closing the table when restarting it on next page -->
    <lineStyle kind="LINEBELOW" colorName="black" start="0,splitlast" stop="-1,splitlast" thickness="0.5"/>
  </blockTableStyle>
</stylesheet>
<story>
  <h1>$title</h1>
  <blockTable repeatRows="1" style="mynicetable">
    <tr><td py:for="i in range(10)">Row ${i}</td></tr>
    <tr py:for="line in data"><td py:for="col in line" py:content="col" /></tr>
  </blockTable>
  <para py:content="dummy" />
</story>
</document>

Rergardons cette template de plus près :

  • Le noeud template permet de choisir la taille du document
  • Le noeud stylesheet permet de définir une feuille de style
  • Le noeud story contient le contenu du document
  • Comme en html, h1 définit un titre (ici on inclut la variable « title » en contenu)
  • Un para est comme la balise P en html (paragraphe)
  • La table est définie en blockTable. les py:for définissent une iteration
  • Le premier py:for (py:for= »i in range(10) ») permet de définir les colonnes (Row 0 à 9)
  • Le deuxieme (py:for= »line in data ») permet d’afficher tout le contenu de la variable data
  • Le troisième (py:for= »col in line ») permet d’afficher son contenu (avec un py:content, définissant le contenu du tag xml) sur toutes les colonnes

Maintenant utilisons cela pour générer un fichier :

template = 'test.xml'
testdata = [range(10)] * 100

factory.render_template(
        template_file=template,
        title=u'THE TITLE',
        data=testdata,
        dummy='foo')

Ici, on a passé une jeu de données contenant les chiffres 1 à 9, 100 fois (100 listes).
On a aussi passé plusieurs variables utilisées dans la template.

On veut ajouter une autre section avec la même template ? Pas de problème !

factory.render_template(
        template_file=template,
        title=u'THE TITLE 2!',
        data=testdata,
        dummy='bar'
        )

Créons un seul fichier pdf contenant les deux parties, et finalisons l’objet :

factory.render_document('test.pdf')
factory.cleanup()

Et voilà, aussi simple que cela :)

Comment l’installer ?

Pour installer pyjon.reports, c’est simple : « easy_install pyjon.reports », vous pourrez avoir des pdf dans vos applis en 5 minutes.

Si vous voulez regarder les sources ou contribuer, rendez-vous sur bitbucket : http://bitbucket.org/jon1012/pyjonreports

Pour plus d’infos :

Zok likes to watch
louis vuitton outlet Versace for H to debut this Saturday

and the financial
woolrich arctic parkaDifference between Fashion Jewelry and Costume Jewelry