Incorporar Modelos ManyToMany al Backend en Django

diciembre 10, 2009

Uno de los beneficios de usar django para crear nuestra aplicación web es que como por arte de mágia, todo el backoffice de nuestra aplicación se generará ante nuestros ojos sin tirar ni una linea de código.

Parafraseando a Uderzo y Goscinny, ¿Ni una sola linea?, No, alguna, cual aldea Gala indestructible, habrá que tirar, pero ni mucho menos comparable a lo que sería hacerlo desde cero.

Hasta hace poco, si en nuestro modelo exitía una relación Muchos a Muchos, la edición desde la interfaz de administración no era todo lo intuitiva que esperaríamos, pero en la última versión de django este aspecto esta solucionado, proporcionandonos una flexibilidad absoluta.

Supongamos un modelo de un sencillo bloc de notas, inicialmente tendremos dos entidades, una que será las notas y otra que serán los tags que asociamos a dichas notas. La relación entre los tags y las notas es de Muchos a Muchos, el código de dichos modelos sería algo como:

class Note(models.Model):
  title = models.CharField(max_length=200)
  pub_date = models.DateTimeField('date created')
  body = models.TextField()
  tags = models.ManyToManyField('Tag', related_name='notes')

  def __unicode__(self):
    return self.title</div>

class Tag(models.Model):
  name = models.CharField(max_length=100)

  def __unicode__(self):
    return self.name

Por defecto, django nos genera una interfaz de administración que podemos ver si entramos a la aplicación “admin” una vez lanzado el servidor. Si usamos el servidor de desarrollo, la URL habitual es http://localhost:8000/admin/

Como deciamos anteriormente, en las versiones anteriores de django, solo podíamos editar (y personalizar usando Inlines por ejemplo) los elementos de la clase asociada donde se definía la relacion ManyToMany. En nuestro caso, solo podriamos asociar y añadir tags desde la gestión de notas, pero no viceversa. Al ser una relación bidireccional, como vemos esto no es muy útil.

Para personalizar las interfaces de administración debemos editar el fichero admin.py que esta dentro de nuestro proyecto.

Si queremos que la lista de objetos de la clase asociada aparezca de forma linear, podemos crear un objeto derivado de algun sabor de Inline, como por ejemplo TabularInline. La novedad en la nueva versión de django es que a la clase que modela la relación ManyToMany posee un atributo que representa la asociación.

Este atributo se conoce como through, en versiones anteriores, ese parámetro nos servía para indicar un modelo extendido asociado a la relación muchos a muchos, a la hora de declarar la propia relación en el modelo.

Así si usamos las siguientes clases:

class TagNoteInline(admin.TabularInline):
  model = Note.tags.through

class TagAdmin(admin.ModelAdmin):
  inlines = [
    TagNoteInline,
  ]

class NoteAdmin(admin.ModelAdmin):
  inlines = [
    TagNoteInline,
  ]
  exlude = ('tags',)

admin.site.register(Note, NoteAdmin)
admin.site.register(Tag, TagAdmin)

Podremos editar en ambas interfaces la clase correspondiente asociada.

Para finalizar, si no has entendido nada 😉 quizás te interese el maravilloso tutorial que esta en la propia web del django y concretamente la relacionada con la parte de administración: http://docs.djangoproject.com/en/dev/intro/tutorial02/#intro-tutorial02
Anuncios

Django y las Bases de Datos

junio 24, 2009
No se vosotros, pero si algo me gusta poco programar es el típico código para unir nuestras clases del modelo con la base de datos. Una de las grandes desventajas de escribir este código a mano es que es sumamente repetitivo, lo que lleva a muchos errores de copy&paste.
Este aspecto desde luego no es nuevo en el desarrollo de aplicaciones, los requerimientos de persistencia son constantes en una aplicación.
Una primera aproximacion fué las bases de datos orientadas a objetos, recuerdo que en alguna clase de la universidad vimos FastObjects o la extension de Oracle para Objectos, sin embargo esta aproximación no acabo de imponerse. La opción que mas se utilizaba fué usar APIs para traducir los objetos tradicionales a Bases de Datos Relacionales típicas.
Posiblemente esta opción fue la mas extendida por la gran difusión y optimizacion de dichos motores de bases de datos.

django y las bases de datos

No se vosotros, pero si algo me gusta poco programar es el típico código para unir nuestras clases del modelo con la base de datos. Una de las grandes desventajas de escribir este código a mano es que es sumamente repetitivo, lo que lleva a muchos errores de copy&paste.

Este aspecto desde luego no es nuevo en el desarrollo de aplicaciones, los requerimientos de persistencia son constantes en una aplicación.

Una primera aproximacion fué las bases de datos orientadas a objetos, recuerdo que en alguna clase de la universidad vimos FastObjects o la extension de Oracle para Objectos, sin embargo esta aproximación no acabó de imponerse. La opción que mas se utilizaba fué usar APIs para traducir los objetos tradicionales a Bases de Datos Relacionales típicas.

Posiblemente esta opción fue la mas extendida por la gran difusión y optimización de dichos motores de bases de datos.

Hablando de mi experiencia y en el ámbito de los lenguajes “mayores”, es decir Java o C#, empecé experimentando con Hibernate en lo que se refiere a Java y con los DataSource tipados en lo respectivo a .NET.

Mas tarde se publicó finalmente EJB 3.0 y surgió JPA. Lo cual añadio a Java una api bastante decente y además oficial que iba a favorecer bastante la programación de estas labores. Quizás en otro post hablaremos de JPA 😉

Cada evolución y versión de las APIs mejoraban un poco mas lo que teniamos anteriormente, y nos permitia quitarnos cada vez mas codigo de “pegamento” entra la BBDD y nuestras clases.

Según la aplicación, actualmente es posible ahorrarse mucho código de este tipo, lo que sin duda es una gran ventaja.

Todo no son paños calientes y muchas veces no nos quedará mas remedio que seguir programando algunos fragmentos de este tipo de código ya que las APIs no siempre se adaptan a las necesidades que suelen surgir cuando se plasman los requisitos del cliente, sin embargo estos son los casos especiales.

Hablando ya de lo que en esta serie nos preocupa, django nos va a ayudar bastante a la hora de autogenerar este código. De hecho a priori no tendremos que escribir ni una sola sentencia SQL para persistir los datos.

En el anterior post, dejamos el servidor funcionando, ahora vamos a crear una aplicación dentro de ese servidor para poder meter nuestro código. Para ello hay que ejecutar

$ python manage.py startapp bookstore

Y el script manage.py nos creará el directorio bookstore con los ficheros iniciales.

De los ficheros iniciales que nos ha creado el script anterior, vamos a centrarnos en el fichero models.py, por ejemplo digamos que queremos escribir una aplicación para manejar libros, empezaremos creando nuestras clases de modelo,

Para ello editamos el fichero models.py y añadimos la clase que representa a un libro:

from django.db import models
class Book(models.Model):
        author = models.CharField(max_length=100)
        title = models.CharField(max_length=100)
        creationDate = models.DateTimeField('date created')

        def __unicode__(self):
                return self.author + ": " + self.title

La definición de la clase ya nos da muchas pistas de como funciona internamente django. Primero podemos ver que nuestras clases de modelo heredan de models.Model, lo que nos va a proporcionar toda la funcionalidad de búsquedas, creación, etc.

El módulo models nos proporciona métodos para crear las variables de nuestras clases módelo, en lugar de crear tipos básicos de Python. En el ejemplo vemos como crear un campo de Texto o un campo de tipo Fecha.

Una cosa que echamos en falta en el ejemplo es como representar las relaciones entre clases, para ello vamos a modificar ligeramente el ejemplo, extrayendo el campo autor, a una clase nueva, por lo que quedaria algo como:

from django.db import models
class Author(models.Model):
        name = models.CharField(max_length=100)
        birthDate = models.DateTimeField('Birth date')
        def __unicode__(self):
                return self.name

class Book(models.Model):
        author = models.ForeignKey(Author)
        title = models.CharField(max_length=100)
        creationDate = models.DateTimeField('date created')
        def __unicode__(self):
                return self.author + ": " + self.title

Como vemos, usamos la clase ForeignKey para representar la asociación entre libro y autor, el resto de las relaciones también podemos implementarlas sin problemas, usando la clases ManyToMany o OneToOne.

Como siempre, nos gusta ver las cosas funcionando, para ello vamos a usar el comando manage.py para obtener diversas cosas, sin embargo, antes de nada es necesario incluir nuestra aplicación dentro de la lista de aplicaciones instaladas en nuestro proyecto. Para ello editamos el fichero settings.py y añadimos una linea con nuestra aplicación, algo como:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'pruebadjango.bookstore',
)

Siendo “pruebadjango” el nombre de nuestro proyecto

Otro paso necesario es configurar los datos de acceso a la base de datos, para este ejemplo vamos a usar sqlite, una base de datos muy sencilla, que puede residir en un fichero de disco y que viene dentro de la distribución de python, lo que nos va a simplificar mucho las labores de configuración.

Para ello debemos editar de nuevo el fichero settings.py y modificar las lineas:

DATABASE_ENGINE = 'sqlite3'           
DATABASE_NAME = '/home/roberto/Projects/django/bbdd'

Siendo el DATABASE_NAME la ruta al fichero que va a guardar la base de datos.

Una vez añadida la aplicación a la lista ya podemos empezar a ver cositas

El script manage.py tiene diversas utilidades que nos van a servir para ver como django transforma nuestras clases Python a sql. Así por ejemplo si ejecutamos:

$ python manage.py sqlall bookstore

Obtendremos las sentencias SQL generadas para nuestras clases, para nuestro ejemplo la salida es:

BEGIN;
CREATE TABLE "bookstore_author" (
    "id" integer NOT NULL PRIMARY KEY,
    "name" varchar(100) NOT NULL,
    "birthDate" datetime NOT NULL
)
;
CREATE TABLE "bookstore_book" (
    "id" integer NOT NULL PRIMARY KEY,
    "author_id" integer NOT NULL REFERENCES "bookstore_author" ("id"),
    "title" varchar(100) NOT NULL,
    "creationDate" datetime NOT NULL
)
;
CREATE INDEX "bookstore_book_author_id" ON "bookstore_book" ("author_id");
COMMIT;

O también podemos ejecutar:

$ python manage.py validate

Para validar que nuestros modelos estan bien definidos.

Finalmente si ejecutamos:

$ python manage.py syncdb

Se crearan las tablas para nuestros modelos en la base de datos.


Introducción a Django

junio 15, 2009

Django DemoEn el anterior post hablamos en general de los frameworks de desarrollo rápido que habían surgido recientemente. Concretamente nos vamos a centrar en Django por los motivos que comentamos anteriormente.

Django surgió en una redacción de noticias donde requerían una herramienta flexible que les permitiera realizar cambios de una forma ágil. Básicamente el framework nos va a permitir crear aplicaciones basadas en el modelo MVC, que usen operaciones de CRUD ( Create, read, update and delete) o como lo conocemos en español el típico Altas, Bajas Modificaciones y Consultas.

¿De que forma nos va a ayudar?
Principalmente creando toda la lógica de la gestión de nuestras clases con la base de datos.
Además de proporcionarnos toda la API para la gestión de los datos, Django nos va a proporcionar dos cosas adicionales:

  • Una interfaz web genérica auto-generada para gestionar los datos
  • Una API para construir webs que gestionen estos datos.

Durante las sucesivas entradas veremos a ver si realmente el framework nos va a ayudar a crear nuestra aplicación, particularmente en mi contacto con este tipo de frameworks si te adaptas bien a la filosofía del framework nos va a ayudar bastante en la creación de nuestra aplicación.

En este primer post vamos a ver la instalación del framework y después crearemos el esqueleto de nuestro primer proyecto.

A la hora de instalarlo tenemos varias alternativas, si usamos una distribución que incluya django como paquete solo tendremos que instarlo, ahora mismo estoy escribiendo desde Ubuntu 9.04 y solo he tenido que ejecutar apt-get install python-django.
Si nuestra distribución no esta soportada directamente o bien usamos OS X o Windows, debemos bajarnos la ultima versión del sitio web de django ( http://www.djangoproject.com/download/ ) y ejecutar setup.py install con privilegios de administrador.

Una vez que lo tenemos instalado el primer paso es ejecutar el script que va a crear el esqueleto de nuestra aplicación:

$ django-admin startproject pruebadjango

Con esta orden se nos creara un nuevo directorio llamado pruebadjango con los siguientes ficheros relevantes:

  • manage.py: Script que nos va a permitir realizar las diferentes labores de administración sobre la aplicación como gestionar el servidor web embebido que tiene django o la relación con la base de datos
  • settings.py: Fichero que contiene los parámetros de configuración de nuestra aplicacion, como por ejemplo los datos de conexión a la base de datos
  • urls.py: Fichero donde se especifican los mapeos entre las URLs y los paquetes que van a gestionar esa URL, para los que hemos usado Java y sus aplicaciones web, seria una especie de web.xml

Como buen impaciente ;), lo primero que haremos sera ejecutar el servidor, aunque no tiene nada que mostrar, al menos nos confirmará que vamos por el buen camino.

Para ejecutar el servidor debemos escribir:

$ python manage.py runserver

Y si navegamos con el browser a la direccion http://127.0.0.1:8000/ veremos la imagen dela captura, lo que confirmará que tenemos instalado django correctamente y creado nuestro esqueleto que nos va a servir como base en futuras entregas.

Hablando del servidor, una de mis inquietudes con estos frameworks y que aun no ha sido del todo resuelta es como se comportan en entornos donde la exigencia es grande. Aplicaciones web basadas en java reposan en servidores de aplicaciones muy potentes que nos garantizan un buen rendimiento. En este aspecto Grails con Groovy tiene algo ganado, al fin y al cabo es java, y puede aprovecharse de todo lo que apoya a Java. En el caso de frameworks como el que nos ocupa, la fiabilidad viene por Apache y el mod_python. En el ejemplo que hemos propuesto usamos el servidor web embebido en django, sin embargo este servidor solo vale para entornos de desarrollo, a la hora de cambiar a produccion usaremos Apache.