Luego de ver toda la instalación de las librerías y el wrapper de Django (Django-wkhtmltopdf) a través de pip, ahora veremos la configuración del mismo. Lo primero que debemos hacer es dirigirnos al settings.py del proyecto y configurar los valores iniciales de wkhtmltopdf como lo es la consola que usará:
Código :
WKHTMLTOPDF_CMD = “/direccion/al/ejecutable/wkhtmltopdf”
En mi caso quedo de la siguiente manera:
Código :
WKHTMLTOPDF_CMD = “/usr/bin/wkhtmltopdf”
También hay que configurar las opciones de ejecución de la consola en el settings.py, en este caso, un diccionario. Veamos la configuración más simple:
settings.py
Código :
WKHTMLTOPDF_CMD_OPTIONS = { 'quiet':True, }
y por último en las INSTALLED_APPS agregar wkhtmltopdf:
settings.py
Código :
INSTALLED_APPS =( …, 'wkhtmltopdf', …., )
Luego veremos qué es lo que queremos convertir a pdf, en mi caso seguiré un proyecto el cual tengo 'forkeado' en mi (github). El proyecto trata sobre una tienda online, así que lo que haré es convertir el carrito de compras en una compra real, y hacer una factura en PDF sobre lo que compró el cliente... Quedando así, comienzo por la view.
ventas/views.py
Código :
from wkhtmltopdf.views import PDFTemplateResponse …. def to_pdf(request): def to_pdf(request): c_compra = request.session["carrito_de_compra"] #obtengo el carrito de compras de la session vtotal = 0 # valor donde acumulare el monto total a pagar por el usuario f = Factura.objects.count() + 1 # obtener numero de facturas existentes y le sumo uno, como un preview del n de la fact. for key,value in c_compra.items(): # el carrito es un diccionario, lo recorro key= nombre del prod. # el value es una lista donde la pos 0 es la cantidad y la pos 1 el producto p_pro = value[1].precio # obtengo el valor del producto (se corre esta identacion ojo) iva = value[1].iva # obtengo el iva aplicado al producto p_total = (float(p_pro)*(1+iva))*float(value[0]) # obtengo el valor total del producto x iva x cantidad value.append(p_total) # agrego al final de la lista (value) del diccionario el valor total vtotal += p_total # sumatoria de los valores totales fecha = date.today() # obtengo la fecha de hoy return PDFTemplateResponse(request,"ventas/factura.html", {"vtotal":vtotal,"productos":c_compra,"fecha":fecha,"nf":f}) ....
Ojo, si se corre una linea, queda sin identación
y hacer la respectiva llamada a la view desde el url.py
ventas/url.py
Código :
…. url(r'^topdf/$','to_pdf',name= "to_pdf"), ….
Recuerda que en tu template, debes tener definido una etiqueta meta de la siguiente manera...
Código :
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
En mi caso, tengo un template de la siguiente manera...
Aquí primero colocaré el style que está dentro de mi html (recordemos que es mejor que esté todo dentro del html que renderizaremos para evitar costos de tiempo, en que la librería haga peticiones por los css).
ventas/facturapdf.html (sólo etiqueta style)
Código :
<style> #page-wrap { width: 80%; font: 14px/1.4 Georgia, serif; } #page-wrap p { border: 0; font: 14px Georgia, Serif; overflow: hidden; resize: none; } #page-wrap table { border-collapse: collapse; } #page-wrap table td,#page-wrap table th { border: 1px solid black; padding: 5px; } #header { width: 40%; margin: 20px 0; background: #222; text-align: center; color: white; font: bold 15px Helvetica, Sans-Serif; text-decoration: uppercase; } #address { width: 250px; height: 150px; float: left; } #customer { overflow: hidden; } #logo { text-align: right; float: right; position: relative; margin-top: 25px; border: 1px solid #fff; max-width: 540px; max-height: 100px; overflow: hidden; } #header{ width:100%} #meta { margin-top: 1px; width: 300px; float: right; } #meta td { text-align: right; } #meta td.meta-head { text-align: left; background: #eee; } #meta td textarea { width: 100%; height: 20px; text-align: right; } #items { clear: both; width: 100%; margin: 30px 0 0 0; border: 1px solid black; } #items th { background: #eee; } #items textarea { width: 80px; height: 50px; } #items tr.item-row td { border: 0; vertical-align: top; } #items td.description { width: 300px; } #items td.item-name { width: 175px; } #items td.description textarea, #items td.item-name textarea { width: 100%; } #items td.total-line { border-right: 0; text-align: right; } #items td.total-value { border-left: 0; padding: 10px; } #items td.total-value textarea { height: 20px; background: none; } #items td.balance { background: #eee; } #items td.blank { border: 0; } #terms { text-align: center; margin: 20px 0 0 0; } #terms h5 { text-transform: uppercase; font: 13px Helvetica, Sans-Serif; border-bottom: 1px solid black; padding: 0 0 8px 0; margin: 0 0 8px 0; } #terms textarea { width: 100%; text-align: center;} #page-wrap textarea:hover, #page-wrap textarea:focus, #items td.total-value textarea:hover, #items td.total-value textarea:focus, .delete:hover { background-color:#EEFF88; } #image{ width:100px; } </style>
y este es mi html:
ventas/facturapdf.html(solo html)
Código :
<html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <body> <div id="page-wrap"> <p id="header">Tienda Online</p> <div id="identity"> <p id="address">{{ user.nombre }} {{ user.apellidos }}<br> {{ user.identificacion }}<br> {{ user.direccion }}<br> Telefono: {{ user.telefono }}<br> Ciudad : {{ user.ciudad }} </p> <div id="logo"> <img id="image" src="/media/images/logo.jpg" alt="logo" /> </div> </div> <div style="clear:both"></div> <div id="customer"> <table id="meta"> <tr> <td class="meta-head">Pre-Factura #</td> <td><p>{{ nf }}</p></td> </tr> <tr> <td class="meta-head">Fecha</td> <td><p id="date">{{ fecha }}</p></td> </tr> <tr> <td class="meta-head">Monto Total</td> <td><div class="due">${{ vtotal }}</div></td> </tr> </table> </div> <table id="items"> <tr> <th>Articulo</th> <th>Descripcion</th> <th>Costo/U.</th> <th>Cant.</th> <th>IVA</th> <th>Precio</th> </tr> {% for key,value in productos.items %} <tr class="item-row"> <td class="item-name"><div class="delete-wpr"><p>{{ value.1.id }}</p></div></td> <td class="description"><p>{{ key }}</p></td> <td><p class="cost">${{ value.1.precio }}</p></td> <td><p class="qty">{{ value.0 }}</p></td> <td><p>{{ value.1.iva }}</p></td> <td><span class="price">${{ value.2 }}</span></td> </tr> {% endfor %} <tr> <td colspan="3" class="blank"> </td> <td colspan="2" class="total-line">Total</td> <td class="total-value"><div id="total">${{ vtotal }}</div></td> </tr> </table> <div id="terms"> <h5>Terminos</h5> <p>El total del envio sera cubierto completamente por el cliente. 15 dias habiles para la devolucion del producto.</p> </div> </div> </body> </html>
Este ejemplo de factura en html, lo obtuve de CSS-Tricks a ellos el mérito del html de la factura, yo sólo lo adecué e hice el proceso para convertirlo a pdf. Les dejo aquí una imagen del resultado del renderizado:
Y eso es todo, espero que les guste este post. Cualquier cosa estaré respondiendo los comentarios muchísimas gracias por leer tan largo post jeje
¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.
Por minrockx el 08 de Junio de 2013
Por Mariux el 17 de Junio de 2013
minrockx :
podes respostear el tuto como iría finalmente? así no borro partes por equivocación. gracias
Por abarreracon el 26 de Julio de 2013
Por minrockx el 27 de Julio de 2013
abarreracon :
De hecho de esta manera se genera el pdf on the fly y se guarda en una carpeta temporal asi q no gastas espacio en disco.
Por el 30 de Julio de 2013
Por minrockx el 30 de Julio de 2013
https://github.com/minrock/demo
Por Cristian el 14 de Septiembre de 2013
Por luisma el 01 de Octubre de 2013
Por Cloki el 15 de Noviembre de 2013
Por Eder Juarez el 02 de Enero de 2014
Por minrockx el 02 de Enero de 2014
Eder Juarez-blog :
Si estas sirviendo correctamente los archivos "Media"? o los estáticos, debes tener en cuenta que la URL quede accesible, yo allí utilizo una URL directa, pero podrías utilizar también la función reverse de las tags de templates, espero pueda darte un punto de de referencia para comenzar a buscar tu error
Por minrockx el 02 de Enero de 2014
Eder Juarez-blog :
Si estas sirviendo correctamente los archivos "Media"? o los estáticos, debes tener en cuenta que la URL quede accesible, yo allí utilizo una URL directa, pero podrías utilizar también la función reverse de las tags de templates, espero pueda darte un punto de de referencia para comenzar a buscar tu error
Por nosenose el 02 de Abril de 2014
'NoneType' object has no attribute 'endswith'
Por Mario el 13 de Junio de 2014
Por mch55058 el 13 de Junio de 2014
Por wilzander el 12 de Enero de 2015
WindowsError at /pdf/
[Error 5] Acceso denegado
agradecería su ayuda
Por pATAN el 26 de Enero de 2015
2º en setings.py tenes que poner
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR,'static')
WKHTMLTOPDF_CMD = 'C:/Program files/wkhtmltopdf/bin/wkhtmltopdf.exe' (la ruta del ejecutable del binario)
Saludos
Por Alus el 07 de Febrero de 2015
Alguien pudo arreglarlo?
Por wilder el 27 de Marzo de 2015
ImportError: No module named wkhtmltopdf
Por giovanihgo el 27 de Abril de 2015
INSTALLED_APPS = (
'wkhtmltopdf',
)
Por s el 02 de Junio de 2015
Por antonio el 02 de Junio de 2015
afile:///sfile:/// file:///hfile:///afile:///bfile:///ifile:///lfile:///efile:///sfile:/// file:///pfile:///afile:///rfile:///afile:/// file:///lfile:///afile:///
en todo la pagina.. Gracias
Por GOAC1991 el 24 de Febrero de 2016