BLOG

Our thoughts and feelings about our work

Cómo mejorar los procesos internos de una empresa

Cómo mejorar los procesos internos de una empresa

Andres Quiroga Andres Quiroga wrote this on Dec 23, 2016

Con el constante avance de la tecnología es fundamental estar monitoreando los procesos internos de una empresa con el fin de detectar de qué manera es posible mejorar y estar siempre actualizados.


Personalizando el sitio de administración de django.

Andres Quiroga Andres Quiroga wrote this on Aug 17, 2012
El sitio de administración de django es fácil de configurar, simple de usar y los estilos por defecto son elegantes. En conclusión, el sitio de administración de django es una verdadera maravilla, y un punto diferencial de este framework con respecto a otros. A pesar de esto, muchas veces nos hemos visto en la necesidad de personalizarlo, ya sea por requerimientos del proyecto como tal, o por el simple deseo de tener una interfaz de usuario diferente. Una de las opciones que tenemos para modificar los estilos y el javascript nos la ofrece propiamente django, permitiendo agregar media definitions a las vistas de agregar y cambiar un objeto determinado. Definendo los media definitions de esta manera, simplemente debemos indicar la ruta a los archivos my_styles.css y archivo my_code.js para personalizar el formulario de agragar/edición de un objeto del modelo Article. Otra opción para cambiar los estilos que por defecto nos ofrece django en nuestro sitio de administración, son las librerías que nos dan otras alternativas basadas en la interfaz de administración de django, como Grappelli 2.3.8, compatible con django 1.3, y la recientemente actualizada versión Grappelli 2.4.0, compatible con django 1.4. Las anteriores alternativas son útiles en los casos en que los cambios que queremos hacer no sean muy significativos o, cuando simplemente deseemos tener una interfaz de administración que luzca diferente a la que por defecto nos ofrece django. Pero, su uso se puede complicar en la medida en que queramos agregar mas javascript a nuestras plantillas, cuando los cambios empiecen a abarcar la todalidad de la navegabilidad del sitio de administración, y cuando nosotros mismos queremos sobreescribir la totalidad del css. Cuando este sea el caso, vamos a tener la necesidad de tener un sistema de plantillas a la mano, totalmente editable, que nos permita escribir javascript específico por cada plantilla de forma ordenada (usando compressor), definir estilos como nos plazca y definir distintos comportamientos dependiendo de las variables actuales (Si estamos en la lista de los objetos de un modelo específico o en un formulario determinado). django-admin-templates-twitter-bootstrap es una librería que nos permite integrar nuestro sítio de administración con twitter bootstrap (otra opción que al igual que Grappelli, nos ofrece una interfaz alternativa), pero que ademas, nos brinda el "Sistema de plantillas del sitio de administración de django", con el cual tenemos a nuestra dispoción cada plantilla, y nos permite editar contenidos, clases, introducir de forma simple nuevas funcionalidades, definir templatetags... En fin, nos permite tener todo el sitio de administración para que lo personalicemos totalmente como nos plazca. Todo lo que debemos hacer para iniciar es descargar la carpeta admin del repositorio, y agregarla a nuestra carpeta templates en la carpeta principal de nuestro proyecto (La misma en la que tenemos almacenado el archivo settings.py y nuestra carpeta media). Como por arte de mágia, las nuevas plantillas quedan totalmente integradas con nuestro sitio de administración, y solo resta, comenzar a hacer las modificaciones que queramos. Podemos crear un archivo admin_defaults.js y un admin_styles.css específicos para el administrador, crear funciones de javascript por plantilla utilizando compressor, y además, tenemos una estructura totalemnte ordenada (un base.html, una carpeta de includes, etc) para editar de forma simple nuestro sítio de administración.

Django Mobility

Andres Quiroga Andres Quiroga wrote this on Aug 13, 2012
Django mobility es la forma rápida y sencilla de crear vistas que permiten redirigir a los usuarios a la versión móvil de nuestro sitio web usando la misma url. En este caso vamos a mostrar un ejemplo sencillo pero útil en el que una vista retorna una plantilla distinta, dependiendo de si la petición a la url se hace desde un PC o desde un dispositivo móvil. El primer paso es instalar la librería Django-mobility, mediante el siguiente comando: [gist id = 3341476] En el archivo settings.py, agregamos las siguientes lineas a los middleware classes: Si tenemos una aplicación llamada test, agregamos al archivo urls.py de la misma nuestra url, que va a ser igual, tanto para la versión móvil como para PC. Y en nuestro archivo test/views.py definimos las vista mobile_test. Mediante este código aseguramos que si la petición se hace desde un dispositivo móvil, se muestra al usuario una plantilla determinada, con un marcado específico y que puede recibir distintas variables desde la vista, dependiendo de la cantidad de información que se vaya a mostrar y las diferencias con respecto a la versión de la página para PC. Nuestra carpeta templates para la aplicación test debe tener una estructura determinada para que según la fuente desde donde se solicite la url se cargue la plantilla correcta. La versión de la plantilla para PC la creamos en la carpeta: test/templates/test/test.html Para almacenar nuestras plantillas para la versión móvil, creamos la siguiente carpeta: test/templates/test/mobile/ En esta carpeta crearemos la plantilla test.html para nuestra versión móvil. test/templates/test/mobile/test.html Las plantilla tanto para la versión móvil como para la versión PC deben tener el mismo nombre. Esto simplifica en gran medida el trabajo para implementar una versión móvil para nuestro sitio web. Mas eficiencia, al no ser necesario retornar variables que no se va a usar en la versión móvil pero que si son necesarias en la versión para PC, generar un marcado específico para nuestra plantilla móvil y la posibilidad de tener hojas de estilos distintas para las dos versiones, entre muchas otras son las ventajas que ofrece esta librería. Para mas información sobre django-mobility,  visita su sitio en GitHub  

Generando hojas de cálculo flexibles con Python

Andres Quiroga Andres Quiroga wrote this on Apr 10, 2012
A diario nos encontramos con la necesidad de que nuestros proyectos soporten la generación de informes ordenados, con buena presentación y fácilmente legibles por los usuarios. Ya sea un informe de gastos, un informe de facturación,  una tabla que nos permita visualizar los datos de nuestros contactos o un informe de movimientos y solicitudes mensuales en nuestro sitio web, una hoja de cálculo es la mejor opción a la hora de tener un informe entendible y flexible para el usuario. xlwt es una librería de python creada por John Machin, que permite generar hojas de cálculo flexibles. compatibles con Office, OpenOffice, Calc, Gnumeric y con total soporte para Unicode, y a la vez permite personalizar los archivos generados. En este articulo enumeraremos algunas de las herramientas que nos brinda xlwt e iremos paso a paso, detallando el código para obtener un informe final con  nuestras preferencias de personalización. 1. GENERANDO LIBRO La clase WorkBook() nos permite asignar a una variable las características de un archivo xls. Todo libro o archivo xls debe contar con al menos una hoja de cálculo. Las hojas de cálculo se crean por medio del método  add_sheet('nombre_de_la_hoja'). A continuación, se describe el código básico para generar un libro de trabajo llamado first_book.xls, con dos hojas de calculo vacías(first_sheet y second_sheet).
  1. from xlwt import Workbook
  2. def first_book():
  3. # Workbook asing
  4. first_book=Workbook()
  5. # Sheets definition
  6. first_book.add_sheet('first_sheet')
  7. first_book.add_sheet('second_sheet')
  8. # Saving file
  9. first_book.save('first_book.xls')
Para manipular las distintas hojas de cálculo y así definir los contenidos deseados para cada una de ellas, asignamos variables a estas, de la siguiente forma:
  1. from xlwt import Workbook
  2. def first_book():
  3. # Workbook asing
  4. first_book=Workbook()
  5. # Sheets definition
  6. ws1 = first_book.add_sheet('first_sheet')
  7. ws2 = first_book.add_sheet('second_sheet')
  8. # Saving file
  9. first_book.save('first_book.xls')
2. IMPRIMIENDO DATOS Las hojas de cálculo cuentan con el método write, que nos permite introducir contenido en las celdas. Los parámetros que recibe son la posición (celda) y contenido. La posición se introduce de la forma (fila, columna), empezando por la posición (0, 0), equivalente en nuestra hoja a la celda A1. En la siguiente modificación a nuestra función, se introduce, en la hoja de trabajo first_sheet, en la posición A1, el texto "Content 1, sheet 1", y en la posición B1, el texto "Content 2, sheet 1". De la misma forma, en la hoja de cálculo second_sheet, se introduce, en la posición A2, el texto "Content 1, sheet 2", y en la posición B2, el texto "Content 2, sheet 2".
  1. from xlwt import Workbook
  2. def first_book():
  3. # Workbook asing
  4. first_book=Workbook()
  5. # Sheets definition
  6. ws1 = first_book.add_sheet('first_sheet')
  7. ws2 = first_book.add_sheet('second_sheet')
  8. # content per sheets
  9. ws1.write(0, 0, 'Content 1, sheet 1')
  10. ws1.write(0, 1, 'Content 2, sheet 1')
  11. ws2.write(1, 0, 'Content 1, sheet 2')
  12. ws2.write(1, 1, 'Content 2, sheet 2')
  13. # Saving file
  14. first_book.save('first_book.xls')
Pero introducir uno a uno el contenido de cada una de las celdas resultaría ser el proceso mas ineficiente posible a la hora de generar un informe xls. Por tal razón, utilizaremos los bucles de python para imprimir estos contenidos de forma automática. Ahora generaremos una sola hoja de cálculo, en la cual imprimiremos una tabla que relaciona nombre y edad de una sería de personas que se han definido previamente en un diccionario llamado ages.
  1. from xlwt import Workbook
  2. ages={
  3. 'Peter': 20,
  4. 'Karen': 19,
  5. 'Jessie': 43,
  6. 'Leonard': 56,
  7. 'Robert': 30,
  8. 'Nina': 23,
  9. }
  10. number_of_elements = len(ages)
  11. def first_book():
  12. first_book=Workbook()
  13. # Sheet definition
  14. ws1 = first_book.add_sheet('first_sheet')
  15. # Header definition
  16. ws1.write(0, 0, 'Name')
  17. ws1.write(0, 1, 'Years old')
  18. # Represents the first row in the iteration
  19. i = 1
  20. for name, years in ages.items():
  21. ws1.write(i, 0, name)
  22. ws1.write(i, 1, years)
  23. i += 1
  24. if i == number_of_elements+1: # For display the latest element
  25. break
  26. # Saving file
  27. first_book.save('first_book.xls')
Primero definimos el header de la tabla. Asignamos como contenido a la celda A1 (posición 0, 0) el texto "Name", y a la celda B1 (posición 0, 1) el texto "Years old". A continuación definimos la variable i, que representa el número de la fila desde la cual vamos a empezar a imprimir la información de las personas de nuestro diccionario. En este caso, como la fila 1 se encuentra ocupada con el header de la tabla, debemos empezar a introducir los datos desde la fila 2, es decir, desde la posición (1, #-columna). Con un bucle for en el que iteramos el diccionario ages, introducimos de forma ordenada los datos de las personas en nuestra tabla. Por cada ciclo aumentamos el valor de i en 1, y de esta forma imprimimos los datos de cada persona del diccionario en una fila distinta. Previamente habíamos definido la variable number_of_elements, asignándole como valor el número equivalente a la cantidad de elementos del diccionario ages. Esta variable es de gran importancia en este ejemplo, ya que es la clave para salir del bucle y evitar errores de sobre-escritura en las celdas de nuestro archivo first_book.xls. Rompemos el bucle cuando la variable i sea igual a number_of_elements + 1.¿Porque?... La cantidad de elementos en nuestro diccionario es 6 y el valor inicial de la variable i es 1. Por lo tanto, si rompemos el bucle cuando la variable i sea igual a 6, solo estaríamos repitiendo el ciclo 5 veces, es decir, perderíamos el último elemento de nuestro diccionario. 3. PERSONALIZANDO LA PRESENTACIÓN haciendo uso de las clases Font, XFStyle y Borders, podemos añadir preferencias de visualización para nuestras celdas y sus contenidos. A continuación se muestra como personalizar nuestra hoja de cálculo mediante el uso de solo unas pocas de las muchas opciones que brinda xlwt.
  1. from xlwt import Workbook
  2. from xlwt import Font
  3. from xlwt import XFStyle
  4. from xlwt import Borders
  5. ages={
  6. 'Peter': 20,
  7. 'Karen': 19,
  8. 'Jessie': 43,
  9. 'Leonard': 56,
  10. 'Robert': 30,
  11. 'Nina': 23,
  12. }
  13. number_of_elements = len(ages)
  14. def first_book():
  15. first_book=Workbook()
  16. # Sheet definition
  17. ws1 = first_book.add_sheet('first_sheet')
  18. header_font = Font()
  19. body_font = Font()
  20. # Header font preferences
  21. header_font.name = 'Times New Roman'
  22. header_font.height = 20 * 15
  23. header_font.bold = True
  24. # Body font preferences
  25. body_font.name = 'Arial'
  26. body_font.italic = True
  27. # Header Cells style definition
  28. header_style = XFStyle()
  29. header_style.font = header_font
  30. borders = Borders()
  31. borders.left = 1
  32. borders.right = 1
  33. borders.top = 1
  34. borders.bottom = 1
  35. header_style.borders = borders
  36. # body cell name style definition
  37. body_style = XFStyle()
  38. body_style.font = body_font
  39. # Header definition
  40. ws1.write(0, 0, 'Name', header_style )
  41. ws1.write(0, 1, 'Years old', header_style )
  42. # Represents the first row in the iteration
  43. i = 1
  44. for name, years in ages.items():
  45. ws1.write(i, 0, name, body_style)
  46. ws1.write(i, 1, years)
  47. i += 1
  48. if i == number_of_elements+1: # For display the latest element
  49. break
  50. # Saving file
  51. first_book.save('first_book.xls')
El parámetro height que representa el tamaño de la fuente, se debe incluir multiplicado por un factor de 20. Es decir, si el tamaño de fuente deseado es 15, entonces se debe incluir el valor 300, o si el tamaño deseado es 20, entonces se debe introducir el valor 400. Una vez definidas nuestras preferencias de personalización, el resultado se envía como el tercer parámetro en el constructor de la celda. Así, en este caso, para las celdas del header enviamos el parámetro header_style, y para las celdas que contienen los nombres de nuestro diccionario enviamos el parámetro body_style 4. COMBINANDO CELDAS Otra funcionalidad muy común a la hora de trabajar con hojas de cálculo, es la posibilidad de combinar celdas. xlwt permite hacer esto de una forma muy simple. A continuación, insertaremos una imagen en el encabezado de la tabla. Para hacer esto, combinaremos una serie de celdas. La forma de hacerlo es sheet_name.write_merge(fila_inicial, fila_final, columna_inicial, columna_final,). Así, se combinarán las celdas comprendidas en el rango indicado. En este caso, combinaremos las celdas comprendidas entre la posición A1 a la B11.  El rango de celdas combinadas y el ancho de las columnas los ajustamos según el tamañ de la imagén a insertar (Este ejemplo esta ajustado para una imagen de 273x180 px ). Este cambio implica mover nuestros datos tantas filas hacia abajo como filas se combinaron para el encabezado. Así, las celdas del header, (Name y years old), se deben ubicar en la fila 12. Nuestra función first_book quedará de la siguiente manera:
  1. def first_book():
  2. first_book=Workbook()
  3. # Sheet definition
  4. ws1 = first_book.add_sheet('first_sheet')
  5. header_font = Font()
  6. body_font = Font()
  7. # Header font preferences
  8. header_font.name = 'Times New Roman'
  9. header_font.height = 20 * 15
  10. header_font.bold = True
  11. # Body font preferences
  12. body_font.name = 'Arial'
  13. body_font.italic = True
  14. # Header Cells style definition
  15. header_style = XFStyle()
  16. header_style.font = header_font
  17. borders = Borders()
  18. borders.left = 1
  19. borders.right = 1
  20. borders.top = 1
  21. borders.bottom = 1
  22. header_style.borders = borders
  23. # body cell name style definition
  24. body_style = XFStyle()
  25. body_style.font = body_font
  26. # Header definition
  27. ws1.write_merge(0, 10, 0, 1,)
  28. # # Adjust columns width acording to the image size
  29. ws1.col(0).width = 8 * 625
  30. ws1.col(1).width = 8 * 625
  31. # Insert image
  32. ws1.insert_bitmap('logo.bmp', 0, 0)
  33. ws1.write(11, 0, 'Name', header_style )
  34. ws1.write(11, 1, 'Years old', header_style )
  35. # Represents the first row in the iteration
  36. i = 12
  37. for name, years in ages.items():
  38. ws1.write(i, 0, name, body_style)
  39. ws1.write(i, 1, years)
  40. i += 1
  41. if i == number_of_elements+12: # For display the latest element
  42. break
  43. # Saving file
  44. first_book.save('first_book.xls')
5. INSERTANDO FORMULAS Ahora, introduciremos el código para implementar una formula que calcule la suma total de las edades de las personas en nuestra tabla. Debemos exportar la clase "Formula" y definir las celdas que se van a operar. En este caso, se muestra el código para explicar el funcionamiento de las formulas en xlwt, aunque en realidad sería mas sencillo hacer el cálculo en nuestro código y enviar el resultado como parámetro de contenido a una celda determinada. Se deben introducir las celdas a operar por su posición en el formato como se identifican las celdas en los archivos xls (ej:A1, B1). El código quedaría como sigue:
  1. from xlwt import Workbook
  2. from xlwt import Font
  3. from xlwt import XFStyle
  4. from xlwt import Borders
  5. from xlwt import Formula
  6. ages={
  7. 'Peter': 20,
  8. 'Karen': 19,
  9. 'Jessie': 43,
  10. 'Leonard': 56,
  11. 'Robert': 30,
  12. 'Nina': 23,
  13. }
  14. number_of_elements = len(ages)
  15. def first_book():
  16. first_book=Workbook()
  17. # Sheet definition
  18. ws1 = first_book.add_sheet('first_sheet')
  19. header_font = Font()
  20. body_font = Font()
  21. # Header font preferences
  22. header_font.name = 'Times New Roman'
  23. header_font.height = 20 * 15
  24. header_font.bold = True
  25. # Body font preferences
  26. body_font.name = 'Arial'
  27. body_font.italic = True
  28. # Header Cells style definition
  29. header_style = XFStyle()
  30. header_style.font = header_font
  31. borders = Borders()
  32. borders.left = 1
  33. borders.right = 1
  34. borders.top = 1
  35. borders.bottom = 1
  36. header_style.borders = borders
  37. # body cell name style definition
  38. body_style = XFStyle()
  39. body_style.font = body_font
  40. # Header definition
  41. ws1.write_merge(0, 10, 0, 1,)
  42. # # Adjust columns width acording to the image size
  43. ws1.col(0).width = 8 * 625
  44. ws1.col(1).width = 8 * 625
  45. # Insert image
  46. ws1.insert_bitmap('logo.bmp', 0, 0)
  47. ws1.write(11, 0, 'Name', header_style )
  48. ws1.write(11, 1, 'Years old', header_style )
  49. # Represents the first row in the iteration
  50. i = 12
  51. for name, years in ages.items():
  52. ws1.write(i, 0, name, body_style)
  53. ws1.write(i, 1, years)
  54. i += 1
  55. if i == number_of_elements+12: # For display the latest element
  56. break
  57. # Total cell style
  58. total_font = Font()
  59. total_font.bold = True
  60. total_style = XFStyle()
  61. total_style.font = total_font
  62. ws1.write(i, 0, 'Total', total_style)
  63. # Formula
  64. ws1.write(i, 1, Formula("SUM(B13:B18)"))
  65. # Saving file
  66. first_book.save('first_book.xls')