urls template examples example python html django pdf pdf-generation

python - template - views django example



Render HTML a PDF en el sitio de Django (6)

Acabo de azotar esto para CBV. No se usa en producción, pero genera un PDF para mí. Probablemente necesite trabajar para el lado del informe de errores, pero hasta ahora es el truco.

import StringIO from cgi import escape from xhtml2pdf import pisa from django.http import HttpResponse from django.template.response import TemplateResponse from django.views.generic import TemplateView class PDFTemplateResponse(TemplateResponse): def generate_pdf(self, retval): html = self.content result = StringIO.StringIO() rendering = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result) if rendering.err: return HttpResponse(''We had some errors<pre>%s</pre>'' % escape(html)) else: self.content = result.getvalue() def __init__(self, *args, **kwargs): super(PDFTemplateResponse, self).__init__(*args, mimetype=''application/pdf'', **kwargs) self.add_post_render_callback(self.generate_pdf) class PDFTemplateView(TemplateView): response_class = PDFTemplateResponse

Usado como:

class MyPdfView(PDFTemplateView): template_name = ''things/pdf.html''

Para mi sitio django powered, estoy buscando una solución fácil para convertir páginas dinámicas html a pdf.

Las páginas incluyen HTML y gráficos de la API de visualización de Google (que está basada en JavaScript, pero incluso esos gráficos son obligatorios).


Después de tratar de hacer que esto funcione durante demasiadas horas, finalmente encontré esto: https://github.com/vierno/django-xhtml2pdf

Es una bifurcación de https://github.com/chrisglass/django-xhtml2pdf que proporciona una mezcla para una vista genérica basada en clases. Lo usé así:

# views.py from django_xhtml2pdf.views import PdfMixin class GroupPDFGenerate(PdfMixin, DetailView): model = PeerGroupSignIn template_name = ''groups/pdf.html'' # templates/groups/pdf.html <html> <style> @page { your xhtml2pdf pisa PDF parameters } </style> </head> <body> <div id="header_content"> (this is defined in the style section) <h1>{{ peergroupsignin.this_group_title }}</h1> ...

Use el nombre del modelo que definió en su vista en minúsculas al completar los campos de la plantilla. Como es un GCBV, puede llamarlo como ''.as_view'' en su urls.py:

# urls.py (using url namespaces defined in the main urls.py file) url( regex=r"^(?P<pk>/d+)/generate_pdf/$", view=views.GroupPDFGenerate.as_view(), name="generate_pdf", ),



Pruebe la solución de Reportlab .

Descárguelo e instálelo como de costumbre con la instalación de python setup.py

También necesitará instalar los siguientes módulos: xhtml2pdf, html5lib, pypdf con easy_install.

Aquí hay un ejemplo de uso:

Primero defina esta función:

import cStringIO as StringIO from xhtml2pdf import pisa from django.template.loader import get_template from django.template import Context from django.http import HttpResponse from cgi import escape def render_to_pdf(template_src, context_dict): template = get_template(template_src) context = Context(context_dict) html = template.render(context) result = StringIO.StringIO() pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("ISO-8859-1")), result) if not pdf.err: return HttpResponse(result.getvalue(), content_type=''application/pdf'') return HttpResponse(''We had some errors<pre>%s</pre>'' % escape(html))

Entonces puedes usarlo así:

def myview(request): #Retrieve data or whatever you need return render_to_pdf( ''mytemplate.html'', { ''pagesize'':''A4'', ''mylist'': results, } )

La plantilla:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>My Title</title> <style type="text/css"> @page { size: {{ pagesize }}; margin: 1cm; @frame footer { -pdf-frame-content: footerContent; bottom: 0cm; margin-left: 9cm; margin-right: 9cm; height: 1cm; } } </style> </head> <body> <div> {% for item in mylist %} RENDER MY CONTENT {% endfor %} </div> <div id="footerContent"> {%block page_foot%} Page <pdf:pagenumber> {%endblock%} </div> </body> </html>

Espero eso ayude.


Puede usar el editor de iReport para definir el diseño y publicar el informe en el servidor de informes de jaspe. Después de publicar, puede invocar el resto de la API para obtener los resultados.

Aquí está la prueba de la funcionalidad:

from django.test import TestCase from x_reports_jasper.models import JasperServerClient """ to try integraction with jasper server through rest """ class TestJasperServerClient(TestCase): # define required objects for tests def setUp(self): # load the connection to remote server try: self.j_url = "http://127.0.0.1:8080/jasperserver" self.j_user = "jasperadmin" self.j_pass = "jasperadmin" self.client = JasperServerClient.create_client(self.j_url,self.j_user,self.j_pass) except Exception, e: # if errors could not execute test given prerrequisites raise # test exception when server data is invalid def test_login_to_invalid_address_should_raise(self): self.assertRaises(Exception,JasperServerClient.create_client, "http://127.0.0.1:9090/jasperserver",self.j_user,self.j_pass) # test execute existent report in server def test_get_report(self): r_resource_path = "/reports/<PathToPublishedReport>" r_format = "pdf" r_params = {''PARAM_TO_REPORT'':"1",} #resource_meta = client.load_resource_metadata( rep_resource_path ) [uuid,out_mime,out_data] = self.client.generate_report(r_resource_path,r_format,r_params) self.assertIsNotNone(uuid)

Y aquí hay un ejemplo de la implementación de invocación:

from django.db import models import requests import sys from xml.etree import ElementTree import logging # module logger definition logger = logging.getLogger(__name__) # Create your models here. class JasperServerClient(models.Manager): def __handle_exception(self, exception_root, exception_id, exec_info ): type, value, traceback = exec_info raise JasperServerClientError(exception_root, exception_id), None, traceback # 01: REPORT-METADATA # get resource description to generate the report def __handle_report_metadata(self, rep_resourcepath): l_path_base_resource = "/rest/resource" l_path = self.j_url + l_path_base_resource logger.info( "metadata (begin) [path=%s%s]" %( l_path ,rep_resourcepath) ) resource_response = None try: resource_response = requests.get( "%s%s" %( l_path ,rep_resourcepath) , cookies = self.login_response.cookies) except Exception, e: self.__handle_exception(e, "REPORT_METADATA:CALL_ERROR", sys.exc_info()) resource_response_dom = None try: # parse to dom and set parameters logger.debug( " - response [data=%s]" %( resource_response.text) ) resource_response_dom = ElementTree.fromstring(resource_response.text) datum = "" for node in resource_response_dom.getiterator(): datum = "%s<br />%s - %s" % (datum, node.tag, node.text) logger.debug( " - response [xml=%s]" %( datum ) ) # self.resource_response_payload= resource_response.text logger.info( "metadata (end) ") except Exception, e: logger.error( "metadata (error) [%s]" % (e)) self.__handle_exception(e, "REPORT_METADATA:PARSE_ERROR", sys.exc_info()) # 02: REPORT-PARAMS def __add_report_params(self, metadata_text, params ): if(type(params) != dict): raise TypeError("Invalid parameters to report") else: logger.info( "add-params (begin) []" ) #copy parameters l_params = {} for k,v in params.items(): l_params[k]=v # get the payload metadata metadata_dom = ElementTree.fromstring(metadata_text) # add attributes to payload metadata root = metadata_dom #(''report''): for k,v in l_params.items(): param_dom_element = ElementTree.Element(''parameter'') param_dom_element.attrib["name"] = k param_dom_element.text = v root.append(param_dom_element) # metadata_modified_text =ElementTree.tostring(metadata_dom, encoding=''utf8'', method=''xml'') logger.info( "add-params (end) [payload-xml=%s]" %( metadata_modified_text ) ) return metadata_modified_text # 03: REPORT-REQUEST-CALL # call to generate the report def __handle_report_request(self, rep_resourcepath, rep_format, rep_params): # add parameters self.resource_response_payload = self.__add_report_params(self.resource_response_payload,rep_params) # send report request l_path_base_genreport = "/rest/report" l_path = self.j_url + l_path_base_genreport logger.info( "report-request (begin) [path=%s%s]" %( l_path ,rep_resourcepath) ) genreport_response = None try: genreport_response = requests.put( "%s%s?RUN_OUTPUT_FORMAT=%s" %(l_path,rep_resourcepath,rep_format),data=self.resource_response_payload, cookies = self.login_response.cookies ) logger.info( " - send-operation-result [value=%s]" %( genreport_response.text) ) except Exception,e: self.__handle_exception(e, "REPORT_REQUEST:CALL_ERROR", sys.exc_info()) # parse the uuid of the requested report genreport_response_dom = None try: genreport_response_dom = ElementTree.fromstring(genreport_response.text) for node in genreport_response_dom.findall("uuid"): datum = "%s" % (node.text) genreport_uuid = datum for node in genreport_response_dom.findall("file/[@type]"): datum = "%s" % (node.text) genreport_mime = datum logger.info( "report-request (end) [uuid=%s,mime=%s]" %( genreport_uuid, genreport_mime) ) return [genreport_uuid,genreport_mime] except Exception,e: self.__handle_exception(e, "REPORT_REQUEST:PARSE_ERROR", sys.exc_info()) # 04: REPORT-RETRIEVE RESULTS def __handle_report_reply(self, genreport_uuid ): l_path_base_getresult = "/rest/report" l_path = self.j_url + l_path_base_getresult logger.info( "report-reply (begin) [uuid=%s,path=%s]" %( genreport_uuid,l_path) ) getresult_response = requests.get( "%s%s/%s?file=report" %(self.j_url,l_path_base_getresult,genreport_uuid),data=self.resource_response_payload, cookies = self.login_response.cookies ) l_result_header_mime =getresult_response.headers[''Content-Type''] logger.info( "report-reply (end) [uuid=%s,mime=%s]" %( genreport_uuid, l_result_header_mime) ) return [l_result_header_mime, getresult_response.content] # public methods --------------------------------------- # tries the authentication with jasperserver throug rest def login(self, j_url, j_user,j_pass): self.j_url= j_url l_path_base_auth = "/rest/login" l_path = self.j_url + l_path_base_auth logger.info( "login (begin) [path=%s]" %( l_path) ) try: self.login_response = requests.post(l_path , params = { ''j_username'':j_user, ''j_password'':j_pass }) if( requests.codes.ok != self.login_response.status_code ): self.login_response.raise_for_status() logger.info( "login (end)" ) return True # see http://blog.ianbicking.org/2007/09/12/re-raising-exceptions/ except Exception, e: logger.error("login (error) [e=%s]" % e ) self.__handle_exception(e, "LOGIN:CALL_ERROR",sys.exc_info()) #raise def generate_report(self, rep_resourcepath,rep_format,rep_params): self.__handle_report_metadata(rep_resourcepath) [uuid,mime] = self.__handle_report_request(rep_resourcepath, rep_format,rep_params) # TODO: how to handle async? [out_mime,out_data] = self.__handle_report_reply(uuid) return [uuid,out_mime,out_data] @staticmethod def create_client(j_url, j_user, j_pass): client = JasperServerClient() login_res = client.login( j_url, j_user, j_pass ) return client class JasperServerClientError(Exception): def __init__(self,exception_root,reason_id,reason_message=None): super(JasperServerClientError, self).__init__(str(reason_message)) self.code = reason_id self.description = str(exception_root) + " " + str(reason_message) def __str__(self): return self.code + " " + self.description


https://github.com/nigma/django-easy-pdf

Modelo:

{% extends "easy_pdf/base.html" %} {% block content %} <div id="content"> <h1>Hi there!</h1> </div> {% endblock %}

Ver:

from easy_pdf.views import PDFTemplateView class HelloPDFView(PDFTemplateView): template_name = "hello.html"

Si desea utilizar django-easy-pdf en Python 3, consulte la solución sugerida here .