Discussion:
[pylons-discuss] Dynamically-generated PDF to download
Adam Morris
2015-01-25 06:37:17 UTC
Permalink
I have a view that serves up a page that whose template/css contain both
define screen and print media. Which means the view's renderer provides a
page that serves up html that is formatted for the browser (screen media)
and if the user prints it formatted for the page (the print media). The CSS
that does this is:

<link rel="stylesheet" href="${static_url}css/reports.css" media="screen">
<link rel="stylesheet" href="${static_url}css/reports_pdf.css"
media="print">

I want to add a view that returns a FileResponse, as rendered by the print
media, so that particular location results in a download of that PDF, but I
don't want to repeat code.

I don't want to serve a static asset, I want the PDF to be dynamically
created.

Any ideas on how to tackle this best?

Adam
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Wichert Akkerman
2015-01-25 09:59:31 UTC
Permalink
Post by Adam Morris
<link rel="stylesheet" href="${static_url}css/reports.css" media="screen">
<link rel="stylesheet" href="${static_url}css/reports_pdf.css" media="print">
I want to add a view that returns a FileResponse, as rendered by the print media, so that particular location results in a download of that PDF, but I don't want to repeat code.
I don't want to serve a static asset, I want the PDF to be dynamically created.
Any ideas on how to tackle this best?
Here is an example: https://github.com/wichert/checking/blob/master/src/checking/invoice.py#L306 <https://github.com/wichert/checking/blob/master/src/checking/invoice.py#L306>

The basic approach is: generate your data (in this case the PDF file), create a response object using your data, set the right headers for it and return it from your view.

Wichert.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Adam Morris
2015-01-25 13:40:53 UTC
Permalink
Okay, I get that bit now, and coded it up, but when I go to render it, I
use the pyramid.renderers.render object but obviously it ends up
downloading a corrupted file because it's not even in PDF format.

So does reportlab have something to take that html/css and paint it to a
Canvas or something?

The overall idea here is that I was hoping to be able to define how I want
the PDF output to look at by using CSS.


if pdf:
# I need to build the Response object myself
from pyramid.renderers import render
from pyramid.response import Response

result = render('frontend:templates/student_pyp_report.pt',
dict(
title=title,
report=report,
student=student,
pdf=True
),
request=request)


response = Response(
result,
content_disposition="attachment; filename={}.pdf".format("test"
),
content_type = "application/pdf",
charset="utf-8"
)

return response

else:
return dict(
title=title,
report= report,
student=student,
pdf=False
)
Post by Adam Morris
I have a view that serves up a page that whose template/css contain both
define screen and print media. Which means the view's renderer provides a
page that serves up html that is formatted for the browser (screen media)
and if the user prints it formatted for the page (the print media). The CSS
<link rel="stylesheet" href="${static_url}css/reports.css"
media="screen">
<link rel="stylesheet" href="${static_url}css/reports_pdf.css" media="print">
I want to add a view that returns a FileResponse, as rendered by the print
media, so that particular location results in a download of that PDF, but I
don't want to repeat code.
I don't want to serve a static asset, I want the PDF to be dynamically created.
Any ideas on how to tackle this best?
https://github.com/wichert/checking/blob/master/src/checking/invoice.py#L306
The basic approach is: generate your data (in this case the PDF file),
create a response object using your data, set the right headers for it and
return it from your view.
Wichert.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Wichert Akkerman
2015-01-25 17:17:10 UTC
Permalink
Okay, I get that bit now, and coded it up, but when I go to render it, I use the pyramid.renderers.render object but obviously it ends up downloading a corrupted file because it's not even in PDF format.
You are still rendering a .pt file, so I’m guessing you are generating HTML, not PDF. If you want to generate PDF you will need to use a PDF library.
So does reportlab have something to take that html/css and paint it to a Canvas or something?
I use z3c.rml, which uses RML as input to generate PDF. If you want to use HTML & CSS you’ll need to find a library that can convert HTML to PDF.

Wichert.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Adam Morris
2015-01-26 00:20:54 UTC
Permalink
Okay, I've identified pdfkit but with the following code I get a blank pdf
downloaded, I must be doing something wrong...:

from pyramid.renderers import render
from pyramid.response import Response
import pdfkit
import StringIO


result = render('frontend:templates/student_pyp_report.pt',
dict(
title=title,
report=report,
student=student,
pdf=True
),
request=request)


pdffileio = StringIO.StringIO()
pdffileio.write(result)


pdf_as_string = pdfkit.from_file(pdffileio, False) # False means
return it as a string


response = Response(
pdf_as_string,
content_disposition="attachment; filename={}.pdf".format("test"
),
content_type = "application/pdf",
charset="utf-8"
)


#pdffileio.close()


return response


and the pdf_as_string is just this:

Loading page (1/2)\n[>
] 0%\r[======> ]
10%\r[============================================================]
100%\rPrinting pages (2/2)
\n%PDF-1.4\n1 0 obj\n<<\n/Title (\xfe\xff)\n/Creator (\xfe\xff)\n/Producer
(\xfe\xff\x00Q\x00t\x00 \x004\x00.\x008\x00.\x006)\n/CreationDate
(D:20150126001805)\n>>\nendobj\n2 0 obj\n<<\n/Type /Catalog\n/Pages 3 0
R\n>>\nendobj\n4 0 obj\n<<\n/Type /ExtGState\n/SA true\n/SM 0.02\n/ca
1.0\n/CA 1.0\n/AIS false\n/SMask /None>>\nendobj\n5 0 obj\n[/Pattern
/DeviceRGB]\nendobj\n6 0 obj\n<<\n/Type /Page\n/Parent 3 0 R\n/Contents 7 0
R\n/Resources 9 0 R\n/Annots 10 0 R\n/MediaBox [0 0 595 842]\n>>\nendobj\n9
0 obj\n<<\n/ColorSpace <<\n/PCSp 5 0 R\n/CSp /DeviceRGB\n/CSpg
/DeviceGray\n>>\n/ExtGState <<\n/GSa 4 0 R\n>>\n/Pattern <<\n>>\n/Font
<<\n>>\n/XObject <<\n>>\n>>\nendobj\n10 0 obj\n[ ]\nendobj\n7 0
obj\n<<\n/Length 8 0 R\n/Filter
/FlateDecode\n>>\nstream\nx\x9c\xadP=\x0b\x021\x0c\xdd\xf3+2\x0b\xf6\xd2\x16\xda\xde|\x83\xe0
\x1c\x1d\x1c\xc4A\xce/\xc4;\xac7\xf8\xf7M?\x94\xc3I\xd0\x04\xfa\xf2B>^S-\xfc\x0eO#V\x8d\xbfaW\xb0\xf1@\x82\x0ce\xc3\xe8\xf3iB9\xa1U\x0e\x9d\xd4\xc2\xd8\x9a\r\xbb\x1e\x02\x06h\xa1\xe57b\x00\xa9Rs\x01.x\xad\xc9C\xc7n\x80*\x0b\x80\x9c\xf1\xcd\x8a\xa3\x07*\\2\xbb\xe0f\xcb\xb0/3cA\x0f\xae6Z\xd4i#\xe1uJ\xa5&k\x84$\xe58O\x9f4\x16\x9fa=\xc3\x81\x85\xd5\xc2\x90\xb5\xd2\x92Nk?\xe8/B\xc3\xbbU&\x9f\xb6~\xb17e\xb5f\xf1F\xe2\xfd\x00\xc7\xf8\xf7r\xd1\xbf]\x13[x\x02\***@lMendstream\nendobj\n8
0 obj\n194\nendobj\n3 0 obj\n<<\n/Type /Pages\n/Kids \n[\n6 0 R\n]\n/Count
1\n/ProcSet [/PDF /Text /ImageB /ImageC]\n>>\nendobj\nxref\n0
11\n0000000000 65535 f \n0000000009 00000 n \n0000000120 00000 n
\n0000000881 00000 n \n0000000169 00000 n \n0000000264 00000 n \n0000000301
00000 n \n0000000595 00000 n \n0000000862 00000 n \n0000000420 00000 n
\n0000000575 00000 n \ntrailer\n<<\n/Size 11\n/Info 1 0 R\n/Root 2 0
R\n>>\nstartxref\n979\n%%EOF\n[>
] \rDone
\n
Post by Adam Morris
Okay, I get that bit now, and coded it up, but when I go to render it, I
use the pyramid.renderers.render object but obviously it ends up
downloading a corrupted file because it's not even in PDF format.
You are still rendering a .pt file, so I’m guessing you are generating
HTML, not PDF. If you want to generate PDF you will need to use a PDF
library.
So does reportlab have something to take that html/css and paint it to a
Canvas or something?
I use z3c.rml, which uses RML as input to generate PDF. If you want to use
HTML & CSS you’ll need to find a library that can convert HTML to PDF.
Wichert.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Adam Morris
2015-01-26 04:41:07 UTC
Permalink
Got it working now. Problem was that it was that pdfkit was outputting
everything... even verbose stuff, would have thought that would have been
off. Thanks for your help.
Post by Adam Morris
Okay, I've identified pdfkit but with the following code I get a blank pdf
from pyramid.renderers import render
from pyramid.response import Response
import pdfkit
import StringIO
result = render('frontend:templates/student_pyp_report.pt',
dict(
title=title,
report=report,
student=student,
pdf=True
),
request=request)
pdffileio = StringIO.StringIO()
pdffileio.write(result)
pdf_as_string = pdfkit.from_file(pdffileio, False) # False
means return it as a string
response = Response(
pdf_as_string,
content_disposition="attachment; filename={}.pdf".format(
"test"),
content_type = "application/pdf",
charset="utf-8"
)
#pdffileio.close()
return response
Loading page (1/2)\n[>
] 0%\r[======> ]
10%\r[============================================================]
100%\rPrinting pages (2/2)
\n%PDF-1.4\n1 0 obj\n<<\n/Title (\xfe\xff)\n/Creator (\xfe\xff)\n/Producer
(\xfe\xff\x00Q\x00t\x00 \x004\x00.\x008\x00.\x006)\n/CreationDate
(D:20150126001805)\n>>\nendobj\n2 0 obj\n<<\n/Type /Catalog\n/Pages 3 0
R\n>>\nendobj\n4 0 obj\n<<\n/Type /ExtGState\n/SA true\n/SM 0.02\n/ca
1.0\n/CA 1.0\n/AIS false\n/SMask /None>>\nendobj\n5 0 obj\n[/Pattern
/DeviceRGB]\nendobj\n6 0 obj\n<<\n/Type /Page\n/Parent 3 0 R\n/Contents 7 0
R\n/Resources 9 0 R\n/Annots 10 0 R\n/MediaBox [0 0 595 842]\n>>\nendobj\n9
0 obj\n<<\n/ColorSpace <<\n/PCSp 5 0 R\n/CSp /DeviceRGB\n/CSpg
/DeviceGray\n>>\n/ExtGState <<\n/GSa 4 0 R\n>>\n/Pattern <<\n>>\n/Font
<<\n>>\n/XObject <<\n>>\n>>\nendobj\n10 0 obj\n[ ]\nendobj\n7 0
obj\n<<\n/Length 8 0 R\n/Filter
/FlateDecode\n>>\nstream\nx\x9c\xadP=\x0b\x021\x0c\xdd\xf3+2\x0b\xf6\xd2\x16\xda\xde|\x83\xe0
0 obj\n194\nendobj\n3 0 obj\n<<\n/Type /Pages\n/Kids \n[\n6 0 R\n]\n/Count
1\n/ProcSet [/PDF /Text /ImageB /ImageC]\n>>\nendobj\nxref\n0
11\n0000000000 65535 f \n0000000009 00000 n \n0000000120 00000 n
\n0000000881 00000 n \n0000000169 00000 n \n0000000264 00000 n \n0000000301
00000 n \n0000000595 00000 n \n0000000862 00000 n \n0000000420 00000 n
\n0000000575 00000 n \ntrailer\n<<\n/Size 11\n/Info 1 0 R\n/Root 2 0
R\n>>\nstartxref\n979\n%%EOF\n[>
] \rDone
\n
Post by Adam Morris
Okay, I get that bit now, and coded it up, but when I go to render it, I
use the pyramid.renderers.render object but obviously it ends up
downloading a corrupted file because it's not even in PDF format.
You are still rendering a .pt file, so I’m guessing you are generating
HTML, not PDF. If you want to generate PDF you will need to use a PDF
library.
So does reportlab have something to take that html/css and paint it to a
Canvas or something?
I use z3c.rml, which uses RML as input to generate PDF. If you want to
use HTML & CSS you’ll need to find a library that can convert HTML to PDF.
Wichert.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Jonathan Vanasco
2015-01-26 16:16:07 UTC
Permalink
Just want to give a quick warning that a lot of the pdf libraries use crazy
amounts of memory. I have no experience with pdfkit, and it may behave
differently.

If it causes issues with memory/performance, I usually handle this stuff in
Pyramid one of two ways:

a- I segment out the PDF generating routes to run on their own
server/instance. For example: I run 2 pyramid apps via uwsgi. they're
both the same codebase, but one is only given the PDF traffic and the other
is given everything but the pdf traffic.

b- I push the PDF work into Celery and then use browser polling to refresh
until the PDF is ready. (there are better ways to handle offloading to
celery, that's just the dumbest/easiest).
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Tom Lazar
2015-01-25 18:44:59 UTC
Permalink
Fyi I've had good experiences using phantomjs

Sent from a phone, please excuse the brevity.
Post by Wichert Akkerman
Okay, I get that bit now, and coded it up, but when I go to render it, I use the pyramid.renderers.render object but obviously it ends up downloading a corrupted file because it's not even in PDF format.
You are still rendering a .pt file, so I’m guessing you are generating HTML, not PDF. If you want to generate PDF you will need to use a PDF library.
So does reportlab have something to take that html/css and paint it to a Canvas or something?
I use z3c.rml, which uses RML as input to generate PDF. If you want to use HTML & CSS you’ll need to find a library that can convert HTML to PDF.
Wichert.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
Alex
2018-10-19 10:16:27 UTC
Permalink
I know this thread is quite old but it's probably still relevant. We
created a report tool since generating pdf reports in a web application is
a common problem and none of the existing solutions were optimal for us. We
recently released the first stable version 1.0 of our tool ReportBro:

https://www.reportbro.com

ReportBro contains a designer (javascript plugin) to create report
templates which can easily be integrated in a web application. Server-side
we developed a python package - which you can either download or install
via pip - to create the pdf (or xlsx) file with a given report template.

Alex
Post by Tom Lazar
Fyi I've had good experiences using phantomjs
Sent from a phone, please excuse the brevity.
Okay, I get that bit now, and coded it up, but when I go to render it, I
use the pyramid.renderers.render object but obviously it ends up
downloading a corrupted file because it's not even in PDF format.
You are still rendering a .pt file, so I’m guessing you are generating
HTML, not PDF. If you want to generate PDF you will need to use a PDF
library.
So does reportlab have something to take that html/css and paint it to a
Canvas or something?
I use z3c.rml, which uses RML as input to generate PDF. If you want to use
HTML & CSS you’ll need to find a library that can convert HTML to PDF.
Wichert.
--
You received this message because you are subscribed to the Google Groups
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an
<javascript:>.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discuss+***@googlegroups.com.
To post to this group, send email to pylons-***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pylons-discuss/91d6864f-d84a-4874-a284-6402c920b94c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Continue reading on narkive:
Loading...