Возвращение ответа в формате PDF в Django - PullRequest
2 голосов
/ 24 марта 2011

Я задаю очень похожий вопрос к этому .Я создаю pdf с помощью wkhtmltopdf на сервере Ubuntu в Django.

from tempfile import *
from subprocess import Popen, PIPE

tempfile = gettempdir()+"/results.pdf"
papersize = 'Tabloid'
orientation = 'Landscape'
command_args = "wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl %s" %(orientation, papersize, tempfile)
popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout().read()
popen.terminate()
popen.wait()
response = HttpResponse(pdf_contents, mimetype='application/pdf')
return response

Это приводит к ошибке «нет такого файла или каталога» в строке popen = Popen ...Поэтому я изменил эту строку на

popen = Popen(["sh", "-c", command_args], stdout=PIPE, stderr=PIPE)

, и теперь я получаю сообщение об ошибке "'file' object not callable" в строке pdf_contents = ...добавив .communicate () в строку popen = ..., но я не могу найти выход PDF таким образом.Я должен добавить, что ввод строки command_args в командной строке создает PDF просто отлично.Кто-нибудь может указать мне правильное направление?

Ответы [ 5 ]

3 голосов
/ 24 марта 2011

wkhtmltopdf не выводит содержимое PDF для Popen, чтобы прочитать его.pdf_contents правильно содержит вывод команды (ничего).Вам нужно будет прочитать содержимое выходного файла, если вы хотите вернуть его клиенту (см. Ниже), или пропустить выходной файл и заставить wkhtmltopdf выводить содержимое pdf напрямую,

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')
2 голосов
/ 24 марта 2011

Ваша первая версия терпит неудачу, потому что python не знает, где находится wkhtmltopdf. Python не проверит ваш путь для этого. Ваша вторая версия передает команду оболочке, которая позаботится об этом. Вы достигаете того же эффекта, передавая аргумент shell = True.

Вторая проблема (как уже отмечали другие) заключается в том, что вы вызываете stdout (), когда не должны.

Третья проблема в том, что ваша команда wkhtmltopdf неверна. Вы делаете:

wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl tempfile/results.pdf

Вместо этого вы должны пройти

wkhtmltopdf -O %s -s %s -T 0 -R 0 -B 0 -L 0 http://pdfurl -

Таким образом, wkhtmltopdf запишет вывод в стандартный вывод, и вы можете прочитать его. Если вы передадите другой - в качестве источника, вы можете отправить HTML через стандартный ввод.

1 голос
/ 26 декабря 2013

Я понимаю, что это не использует wkhtmltopdf, но я нахожу это намного чище.

1 голос
/ 24 марта 2011

Причина, по которой вы получаете 'file' object is not callable, заключается в том, что если у вас есть popen объект, stdout - это дескриптор файла, а не метод. Не называйте это, просто используйте это:

popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout.read()
0 голосов
/ 24 марта 2011

Вы можете рассмотреть возможность изменения

popen = Popen(command_args, stdout=PIPE, stderr=PIPE)
pdf_contents = popen.stdout().read()
# ...
response = ...

до

pdf_contents = subprocess.check_output(command_args.split())
response = ...

или в более старых версиях:

process = Popen(command_args.split(), stdout=PIPE, stderr=PIPE)
pdf_contents = process.stdout.read()
response = ...

Я предлагаю вам взглянуть на функцию check_output .

РЕДАКТИРОВАТЬ: Кроме того, не вызывайте terminate (), так как он убьет процесс, не дожидаясь его завершения, что может привести к повреждению PDF. Вам в основном нужно будет использовать wait (), так как он будет ждать завершения процесса (и, следовательно, выводить все, что должен выводить). При использовании функции check_output () вам не нужно об этом беспокоиться, так как она ожидает завершения процесса по умолчанию.

Кроме этого, именование переменной с тем же именем, что и у модуля (я говорю о временном файле), является плохой идеей. Я предлагаю вам изменить его на tmpfile и проверить NamedTeoraryFile s, так как его безопаснее использовать, чем то, что вы делаете сейчас.

...