Django es el entorno de desarrollo web para perfeccionistas con límites de tiempo

Migración de esquemas con django-evolution

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.

Puesta en marcha rápida de django-evolution

  1. Descarga la última versión mediante svn:

    svn checkout http://django-evolution.googlecode.com/svn/trunk/ django-evolution
    
  2. Añade django_evolution al setting INSTALLED_APPS de tu proyecto.

  3. Ejecuta syncdb para que se creen las tablas de django_evolution con la información inicial sobre tus modelos:

    ./manage.py syncdb
    
  4. Modifica los modelos que necesites cambiar

  5. 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
    
  6. 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
    

Django-evolution a fondo

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.

Definir mutaciones de modelos

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 Compártelo: Facebook: Twitter: | Categorías: aplicaciones, modelos, pluggables

Entradas similares

Crear una imagen de nuestros modelos con django-command-extensions

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 ...


oEmbed y Django: incrusta contenidos de servicios web con django-oembed

oEmbed es un formato que permite usar una representación embebida de una URL en sitios web de terceros. La API de oEmbed permite a ...


 
Haystack 1.0 liberado

Hace un par de días se ha liberado la versión 1.0 final de Haystack. Haystack es probablemente la forma más sencilla de añadir ...


Ejecutar tareas automáticas con django-chronograph

Django-chronograph es una aplicación que permite programar la ejecución de tareas automáticas de manage.py utilizando cron. Permite especificar las tareas a realizar y ...


 
 

2 comentarios:

El Thursday 12 de November de 2009 pedro dijo:

Hola Antonio, buen artículo este sobre evolution. Lo comencé a usar ya que soy bastante nuevo y hago muchos cambios sobre la marcha en los modelos, así que evolution me viene muy bien para no tirar todo y volver a generar mis apps.
Se me presentó un problema al cambiar el nombre de un campo CharField. Este campo es requerido, por lo cual evolution me protestó que tenía que tener un valor inicial obligadamente (¿¿¿por qué??? antes -con el nombre viejo- no lo tenía), así que no me dejó cambiarlo. Pero cuando accedo por phpMyAdmin veo que el cambio sí cambió de nombre, pero evolution nunca se dió cuenta del cambio y está 'desactualizado' de la BD. Cómo puedo solucionar esto? Que evolution haga una especie de update de la BD actual.
Gracias de antemano.
Saludos
Pedro

El Wednesday 11 de November de 2009 Pedro dijo:

Hola. Yo de nuevo. Se me ocurrió hacer una tontera de la que no me había dado cuenta antes:
"./manage reset django_evolution"
y funcionó.
Esto sólo cambia el estado inicial de evolution para con su aplicación, no hace ningún cambio en sus BD existentes (aclaro para los que no sepan).
Saludos

Escribe un comentario: