Code


Version 2 (modified by soroosh, 5 years ago) (diff)

--

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. This is TCP client code which connects to a jasper server listening on port 5000 and is part of your django application:

import settings
import socket, pickle

class BridgeClient:
    def __init__(self, f):
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._sock.connect(("127.0.0.1",5000))
        packet = pickle.dumps(f)
        self._sock.send(str(len(packet))+"\n"+packet)
        size = int(self._readline())
        self.raw = self._readbytes(size)
        self._sock.close()

    def get_result(self):
        return (self.raw)

    def _readline(self):
        chars = []
        while 1:
            try:
                char = self._sock.recv(1)
            except:
                char = ''
            if char == '\n':
                break
            chars.append(char)
        return "".join(chars)
    
    def _readbytes(self, n):
        chunks = []
    
        while n > 0:
            try:
                chunk = self._sock.recv(n)
            except:
                chunk = None
            if not chunk:
                raise ServerError("Failed to read response from server")
            chunks.append(chunk)
            n -= len(chunk)
        return "".join(chunks)

def get_report(report, params):
    return report_client.BridgeClient({"report": settings.REPORT_DIR + report,
                                       "params": params,
                                       }).get_result()

You also need jython to run JasperReport TCP server. Here is the code in Jython:

import SocketServer
import pickle
import org.postgresql.Driver
from java.sql.DriverManager import *
import sys
import os.path
import traceback

PATH = (os.path.abspath(os.path.dirname(os.path.realpath(__file__))))
sys.path.append(PATH+"/../")
import settings

from java.util import HashMap;
from net.sf.jasperreports.engine import JasperFillManager,JasperExportManager
from java.lang import System
import java.io.ByteArrayOutputStream
import java.io.FileOutputStream
from net.sf.jasperreports.engine import JRParameter
import java.util.Locale

class BridgeRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        try:
            size = int(self._readline())
            data = self._readbytes(size)
            params = pickle.loads(data)
            host = ""
            if settings.DATABASE_HOST:
                if settings.DATABASE_PORT:
                    host = "//%s:%s/" % (settings.DATABASE_HOST,
                                         str(settings.DATABASE_PORT))
                else:
                    host = "//%s/" % settings.DATABASE_HOST

            connection = getConnection("jdbc:postgresql:"+ host +
                                       settings.DATABASE_NAME,
                                       settings.DATABASE_USER,
                                       settings.DATABASE_PASSWORD)
            h = HashMap()
            for k, v in params["params"].items():
                h.put(k,v)
            h.put(JRParameter.REPORT_LOCALE, java.util.Locale("fa"))
            report = JasperFillManager.fillReport(params["report"], h, connection)
            output = java.io.ByteArrayOutputStream()
            JasperExportManager.exportReportToPdfStream(report, output)
            output.close()
            data =output.toByteArray()
        except:
            self.request.send("0\n")
            print traceback.print_exc()
        else:
            self.request.send(str(len(data))+"\n")
            self.request.send(data)

    def _readline(self):
        chars = []
        while 1:
            try:
                char = self.request.recv(1)
            except:
                char = ''
            if not char:
                self._logException(4, "failed to read response line")
                raise ServerError("Failed to read server reply header")
            if char == '\n':
                break
            chars.append(char)
        return "".join(chars)
    
    def _readbytes(self, n):
        chunks = []
    
        while n > 0:
            try:
                chunk = self.request.recv(1)
            except:
                chunk = None
            if not chunk:
                raise ServerError("Failed to read response from server")
            chunks.append(chunk)
            n -= len(chunk)
        return "".join(chunks)

#server host is a tuple ('host', port)
server = SocketServer.TCPServer(('localhost', 5000), BridgeRequestHandler)
server.serve_forever()

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

And this is a sample view

def hello_pdf(request):
    response = HttpResponse(mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="hello_world.pdf"'
    response.write(get_report("hello.jasper", {
                "title": (u"hello world"),
                }))
    return response

All codes are under the [BSD license http://code.djangoproject.com/file/django/trunk/LICENSE].