Front matter: You’re generating a table inside a PDF document with Reportlab, and one of the cells needs to feature a link to an external website. Links aren’t supported (as far as I know) outside a Paragraph object, but shoving a Paragraph into the table cell results in some pretty fucked up word wrapping and table-cell sizing.
It’s ugly, and unacceptable.
According to the Reportlab mailing list:
Paragraphs behave well inside a table cell with a fixed width.
I won’t even try to re-find the post wherein this valuable nugget lies, but it’s somewhere in the mailing-list archives.
The biggest problem here is: You cannot specify individual widths of table cells to fulfill whatever random “okay, now it works” behavior. When you create a Table object, there’s an optional cell-width argument (colWidths), but it applies across the board to every cell in the table. So, for example, if you have one cell with a number and another with a long string of text, you can’t say, “Make the number cell X wide, and make the text cell Y wide.”
Update August 21, 2008: The above paragraph is completely wrong. See my post “ReportLab Table Cell Follow-Up” for more information.
Of course, you can just leave the cell-width calculation up to the Table class when you instantiate it… but that merely results in the aforementioned fucked up shit.
You see the problem, eh?
My solution is:
1. Create the link within a Paragraph. Again, AFAIK, this is the only way to link.
2. Determine the length of the linked text. Use pdfmetrics.stringWidth.
3. Create a Table with only one cell whose width is that determined in step 2. This makes things “behave”.
4. Drop that Table into the cell of the real Table you actually want displayed in the final PDF.
from reportlab.pdfbase import pdfmetrics from reportlab.platypus import SimpleDocTemplate, Paragraph from reportlab.platypus.tables import Table doc = SimpleDocTemplate('filename_of_pdf') Story =  str = 'linked text' url = '<link href="http://the/actual/url.html">%s</link>' % str L = pdfmetrics.stringWidth(str, your_font_name, your_font_size) inside_Table = Table([[Paragraph(url, your_paragraph_style)]], colWidths=L) real_Table_data = ['a', 'b', inside_Table, 'c', 'd'] t = Table(real_Table_data) Story.append(t) doc.build(Story)
For the most part: Blickity-Blam!
Sometimes the pdfmetrics.stringWidth() call will still cause your shit to wrap, but throw a +1 after the call in the L declaration (to add a single point, which is 1/72 of an inch) and things will work beautifully.