| 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 | }}} |