2đź‘Ť
Your first version fails because python does not know where wkhtmltopdf is located. Python will not check your path for that. Your second version passes the command to a shell which takes care of that. You achieve the same effect by passing a shell=True argument.
The second problem (as others have noted) is that you call stdout() when you shouldn’t.
The third problem is that your wkhtmltopdf command is wrong. You are doing:
wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl tempfile/results.pdf
Instead you should pass
wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl -
That way wkhtmltopdf will write the output to standard output and you can read it. If you pass another – as the source, you can send the html over the standard input.
3đź‘Ť
wkhtmltopdf
is not outputting the contents of the PDF for Popen
to read it. pdf_contents
correctly contains the output of the command (nothing). You will need to read the contents of the output file if you want to return it to the client (see below), or skip the output file and make wkhtmltopdf
output the contents of the pdf directly,
from tempfile import *
from subprocess import Popen, PIPE
tempfile = gettempdir()+"/results.pdf"
command_args = "/path/to/wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl %s" % ('Landscape', 'Tabloid', tempfile)
popen = Popen(["sh", "-c", command_args])
popen.wait()
f = open(tempfile, 'r')
pdf_contents = f.read()
f.close()
return HttpResponse(pdf_contents, mimetype='application/pdf')
1đź‘Ť
The reason you’re getting 'file' object is not callable
is because once you have your popen
object, stdout
is a filehandle, not a method. Don’t call it, just use it:
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout.read()
- [Django]-How to put a value from request.GET as a hidden input in django-crispy-forms
- [Django]-TypeError: add() argument after * must be a sequence, not Subscribers
- [Django]-Humanize in django/python, how to translate
- [Django]-Python – Building wheel for lxml (setup.py) … error
- [Django]-Install hstore extension for django tests
0đź‘Ť
You might want to consider changing
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout().read()
# ...
response = ...
to
pdf_contents = subprocess.check_output(command_args.split())
response = ...
or in older versions:
process = Popen(command_args.split(), stdout=PIPE, stderr=PIPE)
pdf_contents = process.stdout.read()
response = ...
I suggest you take a look at the check_output function.
EDIT: Also, don’t call terminate(), as it will kill the process without waiting it to complete, possibly resulting in a corrupted PDF. You will pretty much only need to use wait(), as it will wait for the process to complete (and thus output all it has to output). When using the check_output() function, you need not to worry about it, as it waits for the process to complete by “default”.
Other than that, naming a variable with the same name as a module (I’m talking about tempfile) is a bad idea. I suggest you to change it to tmpfile and to check out NamedTemporaryFiles as it is safer to use than what you are doing right now.
- [Django]-Foreign Keys clash with related field in Django Model
- [Django]-How to consume XML from RESTful web services using Django / Python?
- [Django]-Python / Django – Exception Value: 'WSGIRequest' object has no attribute 'Meta'
- [Django]-Getting all unique values stored in a many-to-many field
- [Django]-Login and registration form on one page with Django