Django视图将URL转换为PDF使用PyQt
我正在尝试写一个Django的视图,用来返回一个网址的PDF文件。
我使用的是PyQt的webview.print来生成PDF,但我不太确定怎么把这个PDF传递给Django的响应。我试过用QBuffer,但总是搞不定。
这是我目前写的视图:
def pdf(request):
app = QApplication(sys.argv)
bufferPdf = QBuffer()
bufferPdf.open(QBuffer.ReadWrite)
web = QWebView()
web.load(QUrl("http://www.google.com")) #the desired url.
printer = QPrinter()
printer.setPageSize(QPrinter.Letter)
printer.setOrientation(QPrinter.Landscape);
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName("file.pdf")
def convertIt():
web.print_(printer)
print "Pdf generated"
QApplication.exit()
QObject.connect(web, SIGNAL("loadFinished(bool)"), convertIt)
bufferPdf.seek(0)
result = bufferPdf.readData(0)
bufferPdf.close()
sys.exit(app.exec_())
response = HttpResponse(result, mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=coupon.pdf'
return response
提前谢谢你们。
2 个回答
0
这是你例子的一个改写,应该能满足你的需求:
import sys
from PyQt4 import QtCore, QtGui, QtWebKit
class WebPage(QtWebKit.QWebPage):
def __init__(self):
QtWebKit.QWebPage.__init__(self)
self.printer = QtGui.QPrinter()
self.printer.setPageSize(QtGui.QPrinter.Letter)
self.printer.setOrientation(QtGui.QPrinter.Landscape);
self.printer.setOutputFormat(QtGui.QPrinter.PdfFormat)
self.mainFrame().loadFinished.connect(self.handleLoadFinished)
def start(self, url):
self.mainFrame().load(QtCore.QUrl(url))
QtGui.qApp.exec_()
def handleLoadFinished(self):
temp = QtCore.QTemporaryFile(
QtCore.QDir.temp().filePath('webpage.XXXXXX.pdf'))
# must open the file to get the filename.
# file will be automatically deleted later
temp.open()
self.printer.setOutputFileName(temp.fileName())
# ensure that the file can be written to
temp.close()
self.mainFrame().print_(self.printer)
temp.open()
self.pdf = temp.readAll().data()
QtGui.qApp.quit()
def webpage2pdf(url):
if not hasattr(WebPage, 'app'):
# can only have one QApplication, and it must be created first
WebPage.app = QtGui.QApplication(sys.argv)
webpage = WebPage()
webpage.start(url)
return webpage.pdf
if __name__ == '__main__':
if len(sys.argv) > 1:
url = sys.argv[1]
else:
url = 'http://www.google.com'
result = webpage2pdf(url)
response = HttpResponse(result, mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=coupon.pdf'
# do stuff with response...
3
ekhumoro 提供的解决方案是错误的。他给出的代码可以在命令行中运行,但在 Django 的视图中根本无法工作。
很多人都注意到,把 Django 和 QT 线程应用结合起来并不容易,甚至可能根本不可能。你看到的错误就是尝试这样做时常见的一个例子。
在我自己的项目中,我尝试了很多不同的代码组织和分组方式,但始终没有找到解决办法。问题似乎在于(我不是 QT 专家,如果有人有更多信息请纠正我)事件驱动的 QT 应用(任何使用 WebKit 的东西都使用 QT 的事件模型)是围绕一个有效的单例 "QApplication" 构建的。你无法控制这个子应用什么时候退出,以及它的各种资源什么时候被释放。因此,任何使用这个库的多线程应用都需要非常小心地管理它的资源——而在处理各种网络应用的过程中,你对这些资源的控制几乎为零。
一个可能的(虽然有点混乱和不专业)解决方案是创建一个接受命令行参数的脚本,然后在 Django 中作为一个官方的子进程调用这个脚本。你可以使用临时文件来输出结果,然后再把这些结果加载到你的应用中。在读取事件后,你可以直接删除磁盘上的文件。虽然有点麻烦,但有效。
我个人很想听听任何确切知道为什么这这么难,或者有合适解决方案的人——在 Stackoverflow 上有很多关于这个问题的讨论,但大多数都是错误或不完整的解释……