Django, DRY y el client-side

Por sí alguien no lo sabe, Django es un potente framework para el desarrollo de aplicaciones web en Python.
Sigue al pie de la letra la filosofía DRY (Don’t Repeat Yourself).

La verdad es que hace honor al lema, pero como backend que es, entra muy poco en lo relativo al client-side.
Aunque Django se usa como backend de aplicaciones móviles (recomiendo Django REST framework) o incluso como backend para aplicaciones nativas (alguna he hecho con C++/Qt4), la realidad es que el grueso de aplicaciones cliente/servidor hechas con Django son web.

Me he dado cuenta que donde más tiempo invierto a la hora de hacer una webapp es en escribir la lógica JavaScript. A pesar de usar mis propias librerías JS, jQuery, Handlebars y demás herramientas de última tecnología, aun tengo que crear mucho código JS para comunicar vía Ajax. Sin duda no cumple con el principio DRY. Harto de esta situación de ineficiencia me puse a buscar paquetes Django que me ayudarán en esta guerra.

No he encontrado una gran variedad, pero he descubierto un paquete en Github que aunque lleva un año sin recibir actualizaciones cumple con gran parte de lo que quiero.

El paquete se llama Django-puzzledev-jom y es fruto de un estudio universitario de lo que llaman SSMVC (Symmetric Synchronized Model View Controller).

Este paquete crea una serie de ficheros JavaScript para cada uno de los modelos que quieras que sean exportables. Importando estas clases en tu client-side, se hace trivial cualquier tarea CRUD.

Esta es la teoría. En la práctica me he dado cuenta de que aun le falta mucho por pulir. Aún esta lejos de alternativas en otras plataformas como ASP.Net o GWT.

Entre otras cosas. aún esta verde la generación de código JavaScript. Una de sus principales carencias es la inclusión de validadores. Esta tarea es más o menos trivial, ya que conociendo los tipos de datos, añadir una expresión regular para comprobar lo que debe ser un email, un télefono o un dato requerido, no debe ser muy complicado.

Es muy probable que acabe haciendo un fork de esta libreria y mejorarla a mi antojo.
Creo que puede ser una buena inversión de tiempo para agilizar los futuros desarrollos.

 

Anuncios

Cómo instalar una aplicación Django en OpenShift

OpenShift es la plataforma PaaS de Red Hat. Aunque este post trata sobre consejos y experiencia de instalar una app de Django, hay que decir que OpenShift está actualmente montado sobre Amazon Web Services y que utiliza el concepto de recurso (gear o cartucho).  Un “cartucho” puede ser una aplicación web, una base de datos MySql, una instancia de memcached, etc. La cuenta gratuita permite tener 3 cartuchos. La idea es que si tu solución necesita escalar, fácilmente se puede añadir nuevos cartuchos bajo demanda.

Aquí os presento algunos tips o problemas con los que me he encontrado:

  • Lo primero es instalar el toolkit de OpenShift, rhc. Se trata de un script Ruby con el que se puede crear aplicaciones, ver logs, acceder via SSH etc. Se instala con “gem install rhc”. A mi me dio un error al instalar parte de la documentación pero funciona sin problemas.
  • La primera vez que se ejecuta rhc nos pedirá los credenciales de OpenShift (login/password) y permite crear y subir una clave pública de SSH para acceder sin tener que recordar clave alguna.
  • Para acceder vía SSH, ejecutamos “rhc ssh <app>“. Esto llama a SSH utilizando la clave pública. Como usuario, se utiliza un string-ID bastante largo. Al acceder nos situa en el “home” virtualizado: /var/lib/openshift/<UserID>. En ese directorio aparecen los componentes principales de tu aplicación. Para una aplicación Django son: app-root, git y python. La mayoria de los directorios son de sólo lectura. Solo en $HOME/app-root/data, $HOME/app-root/repo y algún que otro directorio podemos escribir.
  • Si necesitamos instalar algún componente Python, deberemos de ejecutar el script de Virtualenv. Esto se hace con “source $HOME//python/virtenv/bin/activate”. Luego ya llamaos a “pip install <paquete>“.
  • En caso de tener que copiar algo vía SCP, deberemos tener cuidado de que el directorio destino tenga permiso de escritura. Esta seria una sintaxis válida “scp <fichero> <userID>@<app>-<cuenta>.rhcloud.com:/var/lib/openshift/<userID>/app-root/data“.
  • El entorno de OpenShift establece un número grande de variables de entorno que será de gran utilidad para configurar tu aplicación. Todas comienzan por “OPENSHIFT_”. Por ejemplo OPENSHIFT_APP_DNS nos da el host,  OPENSHIFT_REPO_DIR el directorio donde se ubica el repositorio o OPENSHIFT_PYTHON_LOG_DIR donde se encuentran los logs de Apache.
  • El equivalente a “service httpd restart” es “ctl_app restart“. Lo utilizaremos cada vez que hagamos algún cambio en la aplicación.
  • La mejor forma de enlazar nuestra aplicación con wsgi es fijarnos en el ejemplo que viene. Apache ejecuta $HOME/app-root/repo/wsgi/application para cada request. Este script prepara el entorno de virtualenv e invoca al manejador wsgi de Django. Debemos ajustar los paths y nuestro “project.settings”.
  • Lo más normal es que durante la instalación de nuestra app nos encontremos con errores tipo 500. Con “rhc tail”, veremos los logs de Apache.
  • Los contenidos estáticos deben ir a $HOME/app-root/repo/wsgi/static, luego debemos configurar correctamente la variable STATIC_ROOT para que apunte al path correcto dentro de settings.py.
  • Si nuestra aplicación usa base de datos, se recomienda la ubicacion $HOME/app-root/data, ya que $HOME/app-root/repo se destina al repositorio de código.
  • Es posible tener una configuración especifica según el entorno de ejecución mirando las variables de entorno. En el ejemplo que viene por defecto, se crea una variable booleana ON_OPENSHIFT dentro settings.py que se usa para determinar la ubicación de la base de datos sqlite3.
  • Si queremos obtener la IP de aquellos que nos visitan, tenemos que usar el meta “HTTP_X_FORWARDED_FOR” en lugar “REMOTE_ADDR”.
  • Por último, si queremos asociar un CNAME a nuestra app, usamos “rhc alias <app> <cname>” para crear dicho alias (imagino que añadirá un ServerAlias a la configuración de Apache).

Sin duda OpenShift es de las plataformas más económicas (o gratis) de hospedar un proyecto Django. Muy recomendable para aplicaciones inicialmente pequeñas o prototipos.

 

Django snippets: Executing standalone scripts

Sometimes it’s necessary run some background or cron tasks in a Django app. For example, you can recollect and email you some stats, purge temporal files, process images, etc.

In these cases, you need access to Django framework but you don’t use neither mod_python, wsgi or manage.py to run it.

I have the following simple snippet for it that works fine in my apps.


#!/usr/bin/env python

import os
import sys

if __name__ == '__main__':

# Setup environ
 os.environ['DJANGO_SETTINGS_MODULE'] = "project_name.settings"
 sys.path.append(<path_to_project_base_dir>)
# Bellow this line, welcome to Django World
# Now you can do things like "from project_name.app_name  import models"

If you want to depth in this topic, you must visit Standalone Django scripts

See you!

Medir el tiempo de respuesta de Django

Midiendo tiempos de respuesta en Django

Midiendo tiempos de respuesta en Django

El tiempo de respuesta de un servicio web es el tiempo que transcurre desde que se realiza una petición hasta que se envía el último byte de respuesta al cliente.

Es vital para las aplicaciones web medir este tiempo con el objeto de optimizar la capacidad de respuesta. Nos interesa por tanto minimizar el tiempo de respuesta.

Para aplicaciones web desarrolladas con el framework Django he desarrollado un middleware sencillo que mide el tiempo de respuesta de proceso desde que Django es “consciente” (Python).

Sin duda el middleware, es una de las características que más me gusta de Django. Permite, entre otras tantas cosas, añadir objetos al request.

Una clase middleware debe tener al menos un método: process_request.

En nuestro caso, tenemos 3 métodos: process_request, process_response y __init__.

La idea es simple. Cuando llega un request, añadimos una marca de tiempo al request (process_request).

Cuando ese request es procesado, obtenemos la diferencia de tiempo y la “logueamos” (process_response).

En __init__ simplemente inicializamos el contexto de logging.

Os dejo el código.

¡Que aproveche! 🙂

import logging
from datetime import datetime
from django.conf import settings
class LogTime(object):

        def __init__(self):

                self.log = logging.getLogger("tm")
                self.log.setLevel(logging.INFO)
                formatter = logging.Formatter('[%(asctime)s] "%(message)s"','%Y-%m-%d %a %H:%M:%S')
                if len(self.log.handlers) == 0:
                        hdlr = logging.FileHandler(settings.LOG_TIME_FILE)
                        hdlr.setFormatter(formatter)
                        self.log.addHandler(hdlr)

        def process_request(self,request):

                request.dtLogTimeStart = datetime.now()

        def process_response(self,request,response):
                if 'dtLogTimeStart' in dir(request):
                        delta = datetime.now()-request.dtLogTimeStart
                        self.log.info("req: %s - time: %i.%06i" % (request.path,delta.seconds,delta.microseconds))
                return response