Novedades en Django 1.4

Y el desarrollo de Django sigue a buen ritmo. La versión 1.4 de este framework fue lanzado hace un par de semanas, y al igual que hice con la versión 1.3, vamos a repasar las novedades que presenta esta nueva versión.

Python 2 vs Python 3

Django tiene una política de soporte de las versiones de Python muy estricto. Hasta ahora tenían soporte de toda la rama v2 de Python desde la versión 2.4 Ahora, acaban de anunciar que dejan de soportar la versión 2.4 (siendo oficialmente soportadas sólo la 2.5, 2.6 y 2.7).

La idea es poder soportar en un futuro Python 3 sin dejar de soportar Python 2, y para ello, se simplifican mucho las cosas si de Python 2 solo hay que soportar desde la v2.5 para arriba (debido a que hay muchos backports de características de Python 3 a partir de esa versión).

En cuanto a la versión que soporte Python 3, aún no es oficial, pero ya hay una rama con el desarrollo bastante avanzado. Se plantea que para lo que sería Django 1.5 o 1.6 se podrá incluir el port.

Estrenando nuevo layout

En un movimiento bastante sorprendente el layout de los proyectos de Django ha cambiado totalmente. Hasta ahora el layout era el siguiente:

mi_proyecto/
    __init__.py
    manage.py
    settings.py
    urls.py
    mi_app/
        __init__.py
        models.py
        ...

A partir de ahora, el layout de los proyectos será el siguiente:

manage.py
mi_proyecto/
    __init__.py
    settings.py
    urls.py
    mi_app/
        __init__.py
        models.py
        ...

Como podéis ver el manage.py pasa a estar en el mismo nivel que la carpeta de nuestro aplicación. Esto arregla una serie de problemas que ocasionaban que se importase más de una vez el mismo módulo, así como unifica la manera de importar módulos en Django.

A partir de ahora, en los ficheros generales del proyecto (en el settings.py por ejemplo) se deberá anteponer el nombre del proyecto al módulo en cuestión (mi_proyecto.urls para importar el urls.py). Los módulos internos a las aplicaciones se seguirán importando como hasta ahora, incluyendo el nombre de la aplicación (mi_app.models para importar el models.py de mi_app).

Este nuevo layout pasará a ser el oficial (y único válido) a partir de la versión 1.6 de Django. En la 1.5 el layout antiguo simplemente lanzará un DeprecationWarning.

Soporte para zonas temporales

Hasta ahora Django usaba valores temporales absolutos en todo el framework. Esto ocasionaba problemas, o directamente carecía de la potencia necesaria para gestionar el hecho de que los usuarios de una web vienen de distinto países, con distintas zonas temporales.

Para solucionar esto, Django usa desde ahora valores temporales relativos, en los que acompaña a cada valor con el huso horario en el que ha sido generado (valores aware). Toda la información guardada en la base de datos, por un campo DateTimeField por ejemplo, se pone en formato UTC, de esta manera pueden transformarse a la zona horaria que esté usando el usuario que visita la página web.

Los cambios que hay que hacer para usar esta nueva API son pocos, ya que Django realiza todos los cambios de manera interna... pero alguno hay, así que veámoslos.

Para empezar para que Django sepa extraer la hora UTC de los valores aportados por los usuarios tendrá que saber en que zona horaria está el susodicho. Para ello intentará primero averiguar si hay alguna zona activada, o en caso contrario, usará la configurada en el settings.py.

Para activar alguna bastará con usar un shorcut proporcionado por Django (dentro de django.utils). Y para saber que zona activar... pues no hay más opción que preguntarle al usuario (típico formulario de en que zona horaria está situado). Una vez obtenida esa información, bastará con activar la zona mientras el usuario esté navegando por el portal (usando un middleware por ejemplo, y guardando el valor de la zona horario en la sesión del usuario).

from django.utils import timezone

class TimezoneMiddleware(object):
    def process_request(self, request):
        tz = request.session.get('django_timezone')
        if tz:
            timezone.activate(tz)

Una vez hecho esto todas las fechas que sean aware aparecerán adaptados al huso horario que tenga activado ese usuario.

Este es el único cambio realmente necesario. Aparte, y solo en los casos en los que usemos nosotros valores absolutos (por ejemplo en el default de un campo de un modelo, si usamos datetime.now) tendremos que cambiarlos para usar valores relativos.

Para esto Django nos proporciona un nuevo shorcut

from django.utils.timezone import now

class Post(models.Model):
    titulo = models.CharField(max_length=50)
    fecha = models.DateTimeField(default=now())

Y así de simple es. Django mostrará por la salida estándar Warnings en caso de que vea que se usa algún valor absoluto donde no se debe.

Nuevo sistema criptográfico

Django ha añadido en esta nueva versión un sistema criptográfico que permite la firma criptográfica de textos (realmente no solo textos, también se pueden firmar estructuras complejas como diccionarios, tuplas...).

Al firmar criptográficamente cierto texto conseguimos lo siguiente:

  • Asegurar que nosotros hemos generado ese texto.
  • Comprobar que no ha sido alterado de ninguna manera.

Esto puede ser muy útil como dicen en la página oficial de Django por ejemplo para generar tokens (como los usados al activar cuentas de usuarios, recuperar contraseñas, ...).

El uso de esta API es muy sencilla.

>>> from django.core.signing import Signer
>>> signer = Signer()
>>> signer.sign('Este texto esta firmado')
'Este texto esta firmado:QXw4TMUiuoRyqKxxLuUqQUGYyDk'
>>> signer.unsign('Este texto esta firmado:QXw4TMUiuoRyqKxxLuUqQUGYyDk')
u'Este texto esta firmado'

Como podemos ver, concatena el texto inicial a la firma. Para realizar la operación usa el valor SECRET_KEY del settings.py por lo que tened mucho cuidado en que no caiga en malas manos ya que en ese caso perdería toda su utilidad.

Como detalles adicionales se puede realizar la firma mediante el uso de un valor salt adicional, para que el mismo texto no genere siempre la misma firma. Y por último, hay una clase adicional llamada TimestampSigner que añade información temporal a la firma.

Mejoras en seguridad

Se ha mejorad la seguridad de Django en varios aspectos.

Para empezar, se ha dejado de usar SHA1 en las contraseñas de los usuarios debido al problema de seguridad que fue encontrado en él hace unos meses. A partir de ahora se usará un algoritmo llamado PBKDF2.

Este cambio es totalmente compatible hacia atrás. Los viejos usuarios seguirán usando el mismo esquema que antes, los que se registren a partir de ahora en vuestras webs, en cambio, usarán el nuevo.

Por otra parte, se ha añadido un nuevo middleware en Django encargado de proteger contra un tipo de ataque llamado ClickJacking. Este ataque se basa en situar un iframe invisible delante de la web para conseguir que el usuario haga click en un enlace sin que sea realmente consciente de ello.

Para solucionarlo, se usa la cabecera X-Frame-Options, que puede evitar que la web sea cargada en un iframe.

Esta nueva proteccción no viene activada predeterminadamente, por lo que para usarla hay que configurarla manualmente en el settings.py.

Otros cambios menores

Algunos cambios menores que se han añadido que merecen la pena señalar son:

  • Se añade la capacidad de crear tests específicos para baterías que usan navegadores web en vivo (como Selenium). Para ello se puede usar la nueva clase LiveServerTestCase.
  • Se añade un fichero al crear un nuevo proyeto, llamado uwsgi.py que ayuda a realizar el deploy de la aplicación mediante WSGI.
  • Se añade un nuevo método para crear muchísimos objetos de un módelo de forma rápida: bulk_create.
  • Se añade un método llamado reverse_lazy que sirve para obtener la URL de una página incluso cuando aún no ha sido cargado el urls.py. De esta manera podremos evitar repetir URLs en ficheros como el settings.py.
  • Se permite internacionalizar URLs.
  • Nuevos templatetags: static y truncatechars.
  • Y mucho, mucho más... ;)

Los que quieran leerse la lista entera (es bastante más amplia que lo expuesto aquí), puede consultar el siguiente enlace, en la web oficial de Django.

Artículos Relacionados

Comentarios