| | 1 | If you need to create high-quality PDF reports, you can use JasperReports with django. JasperReports is writen in Java, so I wrote a TCP client to connect to a JasperReports server. |
| | 2 | This is TCP client code which connects to a jasper server listening on port 5000 and is part of your django application: |
| | 3 | {{{ |
| | 4 | |
| | 5 | import settings |
| | 6 | import socket, pickle |
| | 7 | |
| | 8 | class BridgeClient: |
| | 9 | def __init__(self, f): |
| | 10 | self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| | 11 | self._sock.connect(("127.0.0.1",5000)) |
| | 12 | packet = pickle.dumps(f) |
| | 13 | self._sock.send(str(len(packet))+"\n"+packet) |
| | 14 | size = int(self._readline()) |
| | 15 | self.raw = self._readbytes(size) |
| | 16 | self._sock.close() |
| | 17 | |
| | 18 | def get_result(self): |
| | 19 | return (self.raw) |
| | 20 | |
| | 21 | def _readline(self): |
| | 22 | chars = [] |
| | 23 | while 1: |
| | 24 | try: |
| | 25 | char = self._sock.recv(1) |
| | 26 | except: |
| | 27 | char = '' |
| | 28 | if char == '\n': |
| | 29 | break |
| | 30 | chars.append(char) |
| | 31 | return "".join(chars) |
| | 32 | |
| | 33 | def _readbytes(self, n): |
| | 34 | chunks = [] |
| | 35 | |
| | 36 | while n > 0: |
| | 37 | try: |
| | 38 | chunk = self._sock.recv(n) |
| | 39 | except: |
| | 40 | chunk = None |
| | 41 | if not chunk: |
| | 42 | raise ServerError("Failed to read response from server") |
| | 43 | chunks.append(chunk) |
| | 44 | n -= len(chunk) |
| | 45 | return "".join(chunks) |
| | 46 | |
| | 47 | def get_report(report, params): |
| | 48 | return report_client.BridgeClient({"report": settings.REPORT_DIR + report, |
| | 49 | "params": params, |
| | 50 | }).get_result() |
| | 51 | |
| | 52 | }}} |
| | 53 | |
| | 54 | You also need jython to run JasperReport TCP server. Here is the code in Jython: |
| | 55 | {{{ |
| | 56 | import SocketServer |
| | 57 | import pickle |
| | 58 | import org.postgresql.Driver |
| | 59 | from java.sql.DriverManager import * |
| | 60 | import sys |
| | 61 | import os.path |
| | 62 | import traceback |
| | 63 | |
| | 64 | PATH = (os.path.abspath(os.path.dirname(os.path.realpath(__file__)))) |
| | 65 | sys.path.append(PATH+"/../") |
| | 66 | import settings |
| | 67 | |
| | 68 | from java.util import HashMap; |
| | 69 | from net.sf.jasperreports.engine import JasperFillManager,JasperExportManager |
| | 70 | from java.lang import System |
| | 71 | import java.io.ByteArrayOutputStream |
| | 72 | import java.io.FileOutputStream |
| | 73 | from net.sf.jasperreports.engine import JRParameter |
| | 74 | import java.util.Locale |
| | 75 | |
| | 76 | class BridgeRequestHandler(SocketServer.BaseRequestHandler): |
| | 77 | def handle(self): |
| | 78 | try: |
| | 79 | size = int(self._readline()) |
| | 80 | data = self._readbytes(size) |
| | 81 | params = pickle.loads(data) |
| | 82 | host = "" |
| | 83 | if settings.DATABASE_HOST: |
| | 84 | if settings.DATABASE_PORT: |
| | 85 | host = "//%s:%s/" % (settings.DATABASE_HOST, |
| | 86 | str(settings.DATABASE_PORT)) |
| | 87 | else: |
| | 88 | host = "//%s/" % settings.DATABASE_HOST |
| | 89 | |
| | 90 | connection = getConnection("jdbc:postgresql:"+ host + |
| | 91 | settings.DATABASE_NAME, |
| | 92 | settings.DATABASE_USER, |
| | 93 | settings.DATABASE_PASSWORD) |
| | 94 | h = HashMap() |
| | 95 | for k, v in params["params"].items(): |
| | 96 | h.put(k,v) |
| | 97 | h.put(JRParameter.REPORT_LOCALE, java.util.Locale("fa")) |
| | 98 | report = JasperFillManager.fillReport(params["report"], h, connection) |
| | 99 | output = java.io.ByteArrayOutputStream() |
| | 100 | JasperExportManager.exportReportToPdfStream(report, output) |
| | 101 | output.close() |
| | 102 | data =output.toByteArray() |
| | 103 | except: |
| | 104 | self.request.send("0\n") |
| | 105 | print traceback.print_exc() |
| | 106 | else: |
| | 107 | self.request.send(str(len(data))+"\n") |
| | 108 | self.request.send(data) |
| | 109 | |
| | 110 | def _readline(self): |
| | 111 | chars = [] |
| | 112 | while 1: |
| | 113 | try: |
| | 114 | char = self.request.recv(1) |
| | 115 | except: |
| | 116 | char = '' |
| | 117 | if not char: |
| | 118 | self._logException(4, "failed to read response line") |
| | 119 | raise ServerError("Failed to read server reply header") |
| | 120 | if char == '\n': |
| | 121 | break |
| | 122 | chars.append(char) |
| | 123 | return "".join(chars) |
| | 124 | |
| | 125 | def _readbytes(self, n): |
| | 126 | chunks = [] |
| | 127 | |
| | 128 | while n > 0: |
| | 129 | try: |
| | 130 | chunk = self.request.recv(1) |
| | 131 | except: |
| | 132 | chunk = None |
| | 133 | if not chunk: |
| | 134 | raise ServerError("Failed to read response from server") |
| | 135 | chunks.append(chunk) |
| | 136 | n -= len(chunk) |
| | 137 | return "".join(chunks) |
| | 138 | |
| | 139 | #server host is a tuple ('host', port) |
| | 140 | server = SocketServer.TCPServer(('localhost', 5000), BridgeRequestHandler) |
| | 141 | server.serve_forever() |
| | 142 | }}} |
| | 143 | You need to have these jar files in your classpath: ["itext-1.4.5.jar", "log4j-1.2.jar", "commons-logging.jar", "icu4j.jar", "commons-collections.jar", "commons-digester.jar", "commons-beanutils.jar", "jasperreports-3.0.0.jar"] + JDBC driver to connect to database |
| | 144 | |
| | 145 | And this is a sample view {{{ |
| | 146 | |
| | 147 | def hello_pdf(request): |
| | 148 | response = HttpResponse(mimetype='application/pdf') |
| | 149 | response['Content-Disposition'] = 'attachment; filename="hello_world.pdf"' |
| | 150 | response.write(get_report("hello.jasper", { |
| | 151 | "title": (u"hello world"), |
| | 152 | })) |
| | 153 | return response |
| | 154 | }}} |