Hace un par de días se publicó una importante actualización de seguridad para Django 1.0, 1.1 y la versión de desarrollo. El agujero de seguridad afecta a cualquier aplicación que utiliza campos EmailField ó URLField en sus modelos. El fallo se debe a la validación de direcciones de e-mail y URLs mediante expresiones regulares. Algunas direcciones podían producir un rendimiento negativo en el sistema al aplicarles las expresiones regulares haciendo que el thread correspondiente dejara de responder y se consumieran más recursos de la CPU pudiendo resultar en una denegación de servicio si se hiciera deliberadamente.
Publicado por Antonio Melé el Monday 12 de October de 2009 | 1 comentario | Categorías: modelos, versiones
Algo interesante que nos aporta django-command-extensions es poder crear una representación gráfica de nuestros modelos (o por decirlo de otro modo nuestro esquema de base de datos) con tan sólo un comando. Esto es posible gracias a GraphViz y el resultado es algo parecido a un diseño UML. Para poder utilizar este comando debemos tener instalado pygraphviz y por supuesto la aplicación django_extensions debe estar incluída en el setting INSTALLED_APPS de nuestro proyecto.
Para instalar pygraphviz en Linux nos bastará con utilizar el comando:
apt-get install python-pygraphviz
Una vez hemos instalado django-command-extensions y pygraphviz podremos crear un archivo dot, formato utilizado por GraphViz ó una imagen. En nuestro caso vamos a crear un archivo PNG que incluya los modelos de todas las aplicaciones de nuestro proyecto. Para ello usamos el comando:
./manage.py graph_models -a -g -o mis_modelos.png
Con el parámetro -o especificamos el archivo de imagen en el que queremos que se almacene el resultado. Si sólo queremos incluir los modelos de algunas aplicaciones podemos hacerlo con el siguiente comando:
./manage.py graph_models app1 app2 app3 -o mis_modelos.png
Este ejemplo es de los modelos de la PyCon-Tech, un framework de gestión de conferencias basado en Django:

Publicado por Antonio Melé el Sunday 12 de July de 2009 | 0 comentarios | Categorías: aplicaciones, imágenes, modelos, pluggables, trucos, tutorial
Las migraciones o evoluciones de esquema son las modificaciones que hacemos a modelos ya creados y que afectan a la base de datos. Cuando sincronizamos por primera vez los modelos de nuestra aplicación mediante syncdb se crean las tablas necesarias para los mismos en la base de datos. Si tras esto realizamos cambios en nuestros modelos tendremos que ejecutar el comando manage.py reset aplicacion para que se borren las tablas correspondientes a nuestra aplicación y vuelvan a crearse nuevas tablas a partir de los nuevos modelos.
El problema se nos plantea cuando tenemos que realizar cambios en modelos que ya estamos utilizando para almacenar datos y por lo tanto no podemos eliminar sus tablas para volver a crearlas. Esto ocurre sobre todo en los entornos de producción. Las soluciones principales son 2: Modificar nuestro modelo y realizar manualmente los cambios equivalentes en sus respectivas tablas de la base de datos ó utilizar alguna herramienta de migración de esquemas como django-evolution, South ó dmigrations.
Vamos a ver cómo usar django-evolution para realizar nuestras migraciones de esquema de una forma sencilla.
Descarga la última versión mediante svn:
svn checkout http://django-evolution.googlecode.com/svn/trunk/ django-evolution
Añade django_evolution al setting INSTALLED_APPS de tu proyecto.
Ejecuta syncdb para que se creen las tablas de django_evolution con la información inicial sobre tus modelos:
./manage.py syncdb
Modifica los modelos que necesites cambiar
Ejecuta el comando de administración evolve con el parámetro --hint que inspeccionará tus modelos y te mostrará qué migraciones deben hacerse:
./manage.py evolve --hint
evolve --hint por sí sólo mostrará las migraciones que django-evolution cree que deben hacerse, pero no hará nada. Para realizar las migraciones añade al comando anterior el parámetro --execute si estás de acuerdo con las modificaciones que van a hacerse en el esquema de la base de datos. Se modificarán las tablas de los modelos que han cambiado de acuerdo a las modificaciones que has visto con evolve --hint:
./manage.py evolve --hint --execute
Es bueno utilizar evolve --hint antes de realizar una migración ya que conviene asegurarse de que los cambios que se han realizado en los modelos han sido detectados correctamente por django-evolution. Al utilizar evolve con el parámetro --sql descubrirás el código SQL que va a ejecutar dicha migración:
./manage.py evolve --hint --sql
django-evolution también permite escribir y almacenar migraciones para que las ejecutemos cuando queramos. Esto es útil cuando estás desarrollando una nueva versión de tu aplicación web: Por un lado en producción tendrás la versión estable de tu aplicación con sus correspondientes modelos. Por otro lado tendrás la nueva versión de desarrollo con modificaciones en tus modelos. Todas las migraciones que realices sobre los modelos en la versión de desarrollo tendrás que realizarlas más adelante sobre los modelos de la versión en producción. Almacenar migraciones te simplificará esta tarea, para ello tendrás que definir mutaciones en un archivo.
Ya hemos visto que cuando ejecutamos evolve --hint nos aparece la información de las migraciones que van a hacerse en nuestros modelos. Si por ejemplo tenemos un modelo Autor al que añadimos un campo nuevo llamado lugar como el siguiente (con null=True ya que los autores actuales que existan en la base de datos no tendrán lugar definido):
lugar = models.CharField(max_length=100, null=True)
Al ejecutar ./manage.py evolve --hint nos aparecerá la siguiente migración:
#----- Evolution for mi_aplicacion
from django_evolution.mutations import *
from django.db import models
MUTATIONS = [
AddField('Autor', 'lugar', models.CharField, max_length=100, null=True)
]
#----------------------
Trial evolution successful.
Run './manage.py evolve --execute' to apply evolution.
Se ha detectado que hay que ampliar la tabla de la base de datos con el campo lugar que hemos añadido al modelo Autor. Si nos fijamos, django-evolution nos está dando directamente el código que necesitamos para almacenar la migración, con los import correspondientes y la definición de MUTATIONS (mutaciones de los modelos).
Para guardar nuestras migraciones y poder aplicarlas cuando queramos tenemos que crear un directorio evolutions dentro del directorio de nuestra aplicación y añadirle un archivo __init__.py vacío para que sea interpretado como un módulo de Python. Dentro de evolutions podremos añadir un arhivo .py por cada migración que queramos almacenar. En nuestro caso añadiremos add_lugar.py con el código entre líneas ---- que nos ha dado la ejecución del comando ./manage.py evolve --hint. La estructura de archivos quedará así:
/mi_aplicacion
/evolutions
__init__.py
add_lugar.py
models.py
views.py
Y el contenido del archivo add_lugar.py será:
from django_evolution.mutations import *
from django.db import models
MUTATIONS = [
AddField('Autor', 'lugar', models.CharField, max_length=100, null=True)
]
Por último, ya que generalmente aplicaremos varias migraciones, tenemos que definir el orden en el que deben ejecutarse. Para ello añadimos una lista SEQUENCE a evolutions/__init__.py que contiene el nombre de las migraciones a aplicar por orden. Nuestro __init__.py tendrá:
SEQUENCE = ['add_lugar']
¡Ya hemos almacenado una migración! Ahora no nos hará falta utilizar evolve con el parámetro --hint sino que podremos usarlo directamente: ./manage.py evolve nos mostrará las migraciones que van a hacerse (a partir de las que hemos almacenado y su secuencia). Y ./manage.py evolve --execute las ejecutará.
Publicado por Antonio Melé el Thursday 21 de May de 2009 | 2 comentarios | Categorías: aplicaciones, modelos, pluggables
Cuando usamos un campo con diferentes opciones (choices) en nuestro modelo utilizamos una lista de elementos cada uno con el valor real que se almacenará en la base de datos seguido por la representación legible del dato. Un ejemplo es el siguiente modelo:
ESTILOS_CHOICES = (
('soul', 'Soul'),
('jazz', 'Jazz'),
('hiphop', 'Hip-Hop'),
)
class Artista(models.Model):
estilo=models.CharField(maxlength=10, choices=ESTILOS_CHOICES)
Suponiendo que tenemos una plantilla que recibe un objeto Artista en la variable {{ artista }} normalmente accedemos al valor de sus campos mediante {{ artista.campo }}. Pero al estar usando choices con {{ artista.estilo }} obtendremos el valor almacenado en la base de datos en vez de su representación legible definida en ESTILOS_CHOICES. ¿Cómo acceder a la forma legible del dato? Para ello tenemos la función get_FOO_display() que nos permite acceder al valor legible de cualquier campo del modelo que utilice choices.Basta con usar {{ artista.get_estilo_display }} en nuestra plantilla para mostrar la representación legible del campo.
La información sobre get_FOO_display() se encuentra en la referencia de modelos.
Publicado por Antonio Melé el Sunday 8 de March de 2009 | 0 comentarios | Categorías: modelos, plantillas, trucos
Suscríbete a nuestro feed RSS y al feed de la comunidad para estar al tanto de todo lo que ocurre entorno a Django.
Tú también puedes escribir en éste blog. Para hacerlo basta con que nos digas sobre qué quieres escribir un artículo relacionado con Django.
Utilizar un formulario para modificar 2 modelos
Descubriendo objetos similares por sus etiquetas