Ver Indice Tutorial

En el capítulo anterior vimos cómo poner en marcha nuestro proyecto Django y cómo arrancar una aplicación. Estamos creando un álbum de fotos, hemos preparado un entorno virtual en el que estamos trabajando y tenemos instalado Django y Pillow . También creamos nuestra base de datos con SQLite y un usuario de administración para la aplicación.

En este nuevo post vamos a crear el modelo de datos y lo incluiremos en el administrador que nos ofrece Django para poder gestionarlo sin tener que recurrir a la consola.

Si recordamos la estructura de carpetas que creaba Django para nuestra aplicación, tenemos lo siguiente.

(tutorial)openwebinars@~/aplicaciones/myapps: tree album
album
├── admin.py
├── __init__.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

1 directory, 6 files
(tutorial)openwebinars@~/aplicaciones/myapps:

Es en el fichero models.py donde vamos a definir el modelo de datos para nuestro álbum, lo editamos para dejarlo así:

from django.db import models


class Category(models.Model):
    """ Categorias para clasificar las fotos """
    
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name


class Photo(models.Model):
    """ Fotos del album """

    category = models.ForeignKey(Category, null=True, blank=True)
    title = models.CharField(max_length=50, default='No title')
    photo = models.ImageField(upload_to='photos/')
    pub_date = models.DateField(auto_now_add=True)
    favorite = models.BooleanField(default=False)
    comment = models.CharField(max_length=200, blank=True)

    def __unicode__(self):
        return self.title

Lo primero que hacemos es importar el módulo models ya que cada una de nuestras clases será una subclase de models.Model .

Para nuestra aplicación hemos definido dos clases, Category que representará las distintas categorías en las que podemos clasificar nuestras fotos y Photo que representa las fotos de nuestro álbum. Si las clases que definimos en models.py representan las tablas en nuestra base de datos, las columnas están representadas por las instancias de la clase Field . Nosotros hemos usado los siguientes campos:
CharField: para campos de caracteres . Tiene un argumento obligatorio, max_length .
ImageField: para ficheros con extensiones de imagen . Aquí usamos el argumento upload_to para especificarle en que directorio queremos que se guarden las imágenes de nuestra aplicación.
DateField : para fechas . Al indicarle auto_now_add como True , estamos almacenando la fecha en la que la foto se ha guardado por primera vez.
BooleanField : para valores booleanos , indicándole que el valor por defecto es false, en caso de no definirlo estaríamos usando None como valor por defecto.
ForeignKey : para establecer relaciones entre clases. null y blank para especificar que este campo puede estar vacío.

Además de esto, definimos en cada una de las clases el método __unicode__() de esta forma le podemos indicar como queremos que quede representado cada uno de los objetos , en nuestro caso usaremos el nombre para las categorías y el título para las fotos.

Con el modelo de datos definido podemos trasladarlo a nuestra base de datos, primero ejecutamos el siguiente comando.

(tutorial)openwebinars@~/aplicaciones/myapps: python manage.py makemigrations
Migrations for 'album':
  0001_initial.py:
    - Create model Category
    - Create model Photo
(tutorial)openwebinars@~/aplicaciones/myapps: 

Veremos una salida como esta, que nos indica que se ha creado un fichero, 0001_initial.py en el que están las modificaciones que se harán en la base de datos al ejecutar el siguiente comando.

(tutorial)openwebinars@~/aplicaciones/myapps: python manage.py migrate
Operations to perform:
  Apply all migrations: admin, album, contenttypes, auth, sessions
Running migrations:
  Applying album.0001_initial... OK
(tutorial)openwebinars@~/aplicaciones/myapps: 

Con esto tendremos en la base de datos el modelo que acabamos de definir. Pero antes de probarlo tenemos que editar el fichero settings.py para definir MEDIA_ROOT como:

MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

Lo hacemos porque Django no guarda en la base de datos el fichero si no la ruta donde está el fichero , de forma relativa a esta configuración; Así, nuestras fotos se guardarán en ./media/photos/ .

Ahora ya podemos abrir el shell y probar a grabar la primera imagen.

(tutorial)openwebinars@~/aplicaciones/myapps: python manage.py shell

from album.models import Category, Photo
from django.core.files import File
c = Category(name='Lagos')
c.save()
 
p = Photo(category=c, title='Maly')
f = open('/home/jose/Escritorio/maly.jpg')
p.photo.save('maly.jpg', File(f))

c.name
Out: 'Lagos'

p.title
Out: 'Maly'

p.photo.url
Out: 'photos/maly.jpg'

exit

Podemos ver que se ha creado un nuevo directorio ./media/photos/ que contiene nuestra imagen.

(tutorial)openwebinars@~/aplicaciones/myapps: tree media
media
└── photos
    └── maly.jpg

1 directory, 1 file

Aunque vemos que funciona correctamente, esta forma de trabajar es lenta si se trata de alimentar la base de datos con más de un registro, para hacerlo más llevadero vimos en el capítulo anterior que Django nos ofrecía un administrador con el que poder gestionar el contenido de nuestra app. Vamos a prepararlo.

Lo primero es decirle que queremos que nuestra aplicación, album , aparezca en él. Editámos el fichero ./album/admin.py para dejarlo así.

from django.contrib import admin
from album.models import Category, Photo

admin.site.register(Category)
admin.site.register(Photo)

Iniciamos el servidor de pruebas y vamos a la dirección http://127.0.0.1:8000/admin , entramos con el usuario que creamos en el capítulo anterior y vemos la página principal del administrador .

Imagen 0 en Tutorial de Django: Modelos y BBDD: Donde guardar la información.

Ahora es más fácil crear una categoría nueva y mucho más fácil añadir imagenes. A la derecha de Photos tenemos el boton Add .

Imagen 1 en Tutorial de Django: Modelos y BBDD: Donde guardar la información.

En Category podemos elegir entre las que tenemos creadas o directamente crear una nueva, Montañas en nuestro caso. Abajo a la derecha podemos decidir si guardar y crear otra, guardar y continuar editando o guardar .

También podemos borrar las fotos que tenemos cargadas, con el botón que aparece abajo a la izquierda.

Imagen 2 en Tutorial de Django: Modelos y BBDD: Donde guardar la información.

Al hacerlo detectamos un problema , aunque el registro se ha borrado de nuestra base de datos, vemos que el fichero que contiene la imagen sigue estando en nuestro directorio ./media/photos/ ; Como dijimos antes lo que almacena Django en la base de datos solo es el directorio donde está la imagen.

Para solucionarlo podemos usar las señales . Estas nos informan de cuando está ocurriendo una determinada acción. A nosotros nos interesa saber cuando se está llamando al método delete() de nuestro objeto Photo, de esta forma una vez borrado el registro de la base de datos, podremos borrar la imagen a la que hace referencia.

Volvemos a nuestro fichero models.py y lo editamos .

from django.db.models.signals import post_delete
from django.dispatch import receiver


@receiver(post_delete, sender=Photo)
def photo_delete(sender, instance, **kwargs):
    """ Borra los ficheros de las fotos que se eliminan. """
    instance.photo.delete(False)

Con esto queda solucionado nuestro problema.

En este capítulo hemos visto cómo incluir el modelo de datos y como alimentarlo desde el shell y desde el administrador. En el siguiente post veremos cómo podemos gestionar la información que hemos guardado y como mostrarla.