Modelo de Datos en Django¶
1. Introducción¶
En este tema, aprenderemos cómo manejar la base de datos en Django a través del ORM (Object-Relational Mapping). Este sistema nos permite interactuar con bases de datos relacionales de manera sencilla, sin necesidad de escribir SQL directamente. Django convierte nuestras clases Python en tablas de base de datos, permitiendo definir la estructura de los datos de forma declarativa.
2. Introducción a los ORMs¶
Un ORM (Object-Relational Mapping) es una técnica que permite interactuar con bases de datos mediante objetos en lugar de utilizar SQL directamente. Django ofrece un ORM potente que convierte las clases Python en tablas de base de datos.
Cuando definimos una clase en Django, el ORM mapea la clase a una tabla y cada instancia de clase se mapea a una fila de esa tabla. Además, los atributos de la clase se convierten en columnas de la tabla. Django se encarga de todas las consultas SQL por nosotros.
Vamos a intentar explicarlo con algunas imagenes:
Primero vamos a ver una aplicación web (o de escritorio) típica, con acceso a base de datos utilizando SQL para realizar operaciones CRUD (Create, Read, Update, Delete):
Aplicación con SQL

Vemos en la imagen que la aplicación utiliza el conector de base de datos para ejecutar consultas SQL directamente. Esto puede complicar el desarrollo y mantenimiento del código.
Un ejemplo de código por ejemplo para insertar un nuevo comentario sería:
import sqlite3
def add_comment(name, score, comment):
conn = sqlite3.connect('db.sqlite3')
cursor = conn.cursor()
cursor.execute('''
INSERT INTO comentarios (name, score, comment)
VALUES (?, ?, ?)
''', (name, score, comment))
conn.commit()
conn.close()
De esta manera estamos mezclando código SQL con código Python, lo que puede dificultar la lectura y mantenimiento del código. Además de los problemas de seguridad que puede acarrear (inyección SQL).
Ahora veamos la estructura de una aplicación que utiliza un ORM:
Aplicación con ORM

En este caso, la aplicación interactúa con el ORM, que se encarga de traducir las operaciones en consultas SQL. Esto simplifica el código y mejora la mantenibilidad. Ahora nuestra aplicación trabaja con objetos en lugar de con consultas SQL. Las consultas SQL las genera el ORM automáticamente. Esto independiza nuestro código de la base de datos concreta que estemos utilizando (MySQL, PostgreSQL, SQLite, etc).
Veamos en la siguiente imagen como convierte el ORM cada elemento de la base de datos en una clase y cada dato en un objeto. Cada atributo de la tabla se convierte en un atributo de la clase.
Un ejemplo de código para insertar un nuevo comentario utilizando el ORM de Django sería:
from comentarios.models import Comentario
def add_comment(name, score, comment):
nuevo_comentario = Comentario(name=name, score=score, comment=comment)
nuevo_comentario.save()
Eso sí, nos queda por ver como se define la clase Comentario en el archivo models.py de la app comentarios. Lo veremos en el siguiente apartado.
ORM mapeo

En resumen:
- Una tabla en la base de datos se convierte en una clase en Python.
- Una fila en la tabla se convierte en una instancia de la clase.
- Una columna en la tabla se convierte en un atributo de la clase.
Para acceder a los datos utilizaremos los métodos de las clases en lugar de escribir consultas SQL.
Resumen

Con todo esto ahora es el momento de ver como definir un modelo de datos en Django. Más adelante veremos como realizar consultas a la base de datos utilizando el ORM.
3. Modelo de Datos en Django¶
Django utiliza un ORM para interactuar con bases de datos relacionales como MySQL, PostgreSQL, SQLite, etc. Tal y como hemos visto esto nos permite realizar opreaciones con la base de datos sin utilizar SQL directamente.
Ventajas de usar un ORM:
- Abstracción: No necesitamos conocer SQL ni la estructura de la base de datos.
- Portabilidad: Podemos cambiar de base de datos sin cambiar el código.
- Seguridad: El ORM maneja la sanitización de datos, reduciendo el riesgo de inyección SQL.
- Productividad: Escribir código con un ORM suele ser más rápido y sencillo que escribir SQL.
3.1 Definir un Modelo de Datos¶
Para crear un modelo de datos en Django, debemos definir una clase en el archivo models.py de una app. Cada clase que creemos representará una tabla en la base de datos. Los atributos de la clase representarán las columnas de la tabla.
Estructura de una base de datos y su modelo

En la imagen anterior tenemos una base de datos con dos tablas: clientesy pedidos. La tabla clientestiene la siguiente estructura:
- id: integer, clave primaria
- Nombre: varchar(100), no nulo
- Apellidos: varchar(100), no nulo
La tabla pedidostiene la siguiente estructura:
- id: integer, clave primaria
- cliente_id: integer, clave foránea a la tabla clientes
- fecha: datetime, no nulo
Por tanto tenemos una relación muchos a muchos entre clientes y pedidos. Un cliente puede tener muchos pedidos, y un pedido pertenece a un solo cliente.
En SQL la definición de esta base de datos será:
| Definición SQL de la base de datos | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 | |
Algunos ejemplos de instrucciones SQL para manipular los datos:
| Ejemplos de consultas SQL | |
|---|---|
1 2 3 4 5 6 7 8 | |
Estas son las operaciones que deberíamos hacer si manipulamos directamente la base de datos con SQL. Ahora veamos como definir este mismo modelo de datos utilizando el ORM de Django.
| Definición del modelo de datos en Django | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
CharField para cadenas de texto y DateTimeField para fechas y horas. La relación entre Pedido y Cliente se define utilizando ForeignKey. Las claves primarias (id) se crean automáticamente.
Si ahora queremos realizar las mismas operaciones que antes, pero utilizando el ORM de Django, el código sería:
| Ejemplos de operaciones con el ORM de Django | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
3.2 Crear un modelo de datos para la app comentarios¶
Ahora que conceptualmente hemos entendido como funcionan los ORMs, vamos a ver, en los siguientes temas, primero como crear un modelo de datos en Django y luego como realizar operaciones (CRUD) a la base de datos utilizando el ORM. En este tama nos conformaremos con crar una nueva tabla en la base de datos. Pero eso en Django no se hace directamente. Se hace a través de un modelo de datos que definimos en Python y luego Django se encarga de crear la tabla en la base de datos. Para ello utilizaremos las migraciones.
Utilizaremos el proyecto modularización creado en el tema anterior, con su app comentarios. Vamos a crear un modelo de datos llamado Comentario con los siguientes campos:
- name:
CharField, máximo 255 caracteres, no nulo. - score:
IntegerField, valor por defecto 3, no nulo. - comment:
TextField, máximo 1000 caracteres, puede ser nulo.
3.2.1 Crear el modelo en models.py¶
# comentarios/models.py
from django.db import models
class Comentario(models.Model):
name = models.CharField(max_length=255)
score = models.IntegerField(default=3)
comment = models.TextField(max_length=1000, null=True)
def __str__(self):
return f'Comentario de {self.name} con puntuación {self.score}'
Explicación del código:
name: campo de texto con un máximo de 255 caracteres, obligatorio.score: campo entero con un valor predeterminado de 3.comment: campo de texto, opcional (puede ser nulo).__str__: método para devolver una representación legible del objeto.
En la siguinte tabla podemos ver los tipos de campos más comunes que podemos utilizar en Django:
| Tipo de Campo | Descripción | Parámetros Comunes |
|---|---|---|
CharField |
Campo de texto corto | max_length, null, blank |
TextField |
Campo de texto largo | null, blank |
IntegerField |
Campo de número entero | |
FloatField |
Campo de número decimal | default, null |
BooleanField |
Campo booleano | default |
DateTimeField |
Campo de fecha y hora | auto_now, auto_now_add, null |
ForeignKey |
Clave foránea para relaciones uno a muchos | to, on_delete |
ManyToManyField |
Relación muchos a muchos | to |
OneToOneField |
Relación uno a uno |
Existen muchas más tipos de campos, pero estos son los más comunes. Puedes consultar la documentación oficial de Django para ver todos los tipos de campos disponibles y sus parámetros.
3.2.2 Crear migraciones¶
Después de definir el modelo, debemos crear las migraciones para reflejar este cambio en la base de datos. Para esto, usamos el comando makemigrations.
- Generar las migraciones:
python manage.py makemigrations comentarios
Este comando genera archivos de migración en la carpeta migrations/ de la app comentarios.
- Aplicar las migraciones:
python manage.py migrate
Este comando aplica las migraciones y crea las tablas correspondientes en la base de datos.
Django crea automáticamente un campo id como clave primaria en cada modelo, por lo que no es necesario definirlo manualmente.
3.2.3 Modificar un modelo¶
Si queremos modificar un modelo, como añadir un nuevo campo, debemos seguir estos pasos:
-
Añadir un campo
dateal modeloComentario:- El nuevo campo será un
DateTimeFieldconauto_now_add=True, para que se asigne automáticamente la fecha y hora de creación. - El campo no puede ser nulo.
# comentarios/models.py class Comentario(models.Model): name = models.CharField(max_length=255) score = models.IntegerField(default=3) comment = models.TextField(max_length=1000, null=True) date = models.DateTimeField(auto_now_add=True) def __str__(self): return f'Comentario de {self.name} con puntuación {self.score}' - El nuevo campo será un
-
Generar y aplicar migraciones:
python manage.py makemigrations comentarios python manage.py migrate
Advertencia
Si añadimos un campo no nulo a un modelo existente, Django nos pedirá que proporcionemos un valor por defecto para las filas ya existentes en la base de datos. Si no lo especificamos, Django no nos dejará continuar.
4. Delegación de rutas¶
Cada app en Django puede tener su propio archivo urls.py para gestionar sus rutas.
4.1 Crear urls.py en la app comentarios¶
Ahora que tenemos una app dentro de nuestro proyecto, con su propio urls.py, la pregunta es, ¿cómo hacemos para que las rutas de esta app sean accesibles desde el proyecto principal?. La respuesta la encontramos en la delegación de rutas.
Delegación de rutas
La delegación de rutas consiste en que cada app tenga su propio archivo urls.py para gestionar sus rutas. Luego, en el archivo urls.py del proyecto principal, incluimos las rutas de cada app utilizando la función include.
Pero para poder delegar, primero debemos crear el archivo urls.py en la app comentarios.
Dentro de la app comentarios, vamos a crear una ruta para listar los comentarios. Primero, creamos el archivo urls.py en la app comentarios.
# comentarios/urls.py
from django.urls import path
from django.http import HttpResponse
urlpatterns = [
path('test/', lambda request: HttpResponse('Hola, esta es la app de comentarios')),
]
Este archivo define una ruta /test/ que devuelve un saludo sencillo. Aparentemente y según lo visto en otros temas la manera de acceder a esta ruta sería http://localhost:8000/test/, pero no es así. Para que esta ruta sea accesible, debemos incluirla en el archivo urls.py del proyecto principal. Lo veremos a continuación.
4.2 Incluir las rutas de la app en el proyecto principal¶
En el archivo urls.py del proyecto principal, incluimos las rutas de la app comentarios utilizando include.
# noticias/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('comentarios/', include('comentarios.urls')),
]
En la nueva ruta creada tenemos dos parámetros que nos tenemos que parar a explicar:
-
comentarios/: es el prefijo que se añadirá a todas las rutas definidas encomentarios/urls.py. Esto significa que para acceder a la ruta/test/definida en la appcomentarios, debemos utilizar la URL completa/comentarios/test/. Pero no es obligatorio que el prefijo sea el mismo que el nombre de la app. Podríamos poner cualquier otro nombre, por ejemploreviews/oopiniones/. La URL para acceder a la ruta/test/sería entonces/reviews/test/o/opiniones/test/. -
include('comentarios.urls'): esta función incluye todas las rutas definidas en el archivourls.pyde la appcomentarios. De esta forma, cualquier ruta que definamos encomentarios/urls.pyestará disponible bajo el prefijo especificado. Aquí sí es obligatorio que el nombre de la app sea el mismo que el que hemos puesto eninclude(), ya que es así como Django sabe dónde encontrar el archivourls.pyde la app (carpetacomentariosarchivourls.py).
De esta forma, la ruta /comentarios/test/ devolverá el saludo.
Ha llegado el momento de probarlo. Arrancamos el servidor de desarrollo:
python manage.py runserver
http://localhost:8000/comentarios/test/. Deberíamos ver el mensaje "Hola, esta es la app de comentarios".
Resultado navegador

5. Resumen¶
En este tema, hemos aprendido cómo trabajar con el ORM de Django para crear y gestionar modelos de datos. Hemos visto cómo crear migraciones, aplicar cambios a los modelos y cómo modificar un modelo existente. También hemos aprendido a crear rutas dentro de cada app para organizar mejor nuestras URLs. En próximos temas, aprenderemos a utilizar estos modelos para obtener información con la base de datos que luego mostraremos en las plantillas.
Con todo esto, sí que tendríamos una aplicación que utiliza todos los elementos del modelo MTV (Model-Template-View) de Django.
6. Ejercicio propuesto¶
Ejercicio: Crear una app con un modelo de datos
Crea una app posts con un modelo Post que tenga los siguientes campos:
- title:
CharField, máximo 200 caracteres, no nulo. - content:
TextField, no nulo. - author:
CharField, máximo 100 caracteres, no nulo. - created_at:
DateTimeField,auto_now_add=True, no nulo. - updated_at:
DateTimeField,auto_now=True, no nulo.
Realiza las migraciones necesarias para crear la tabla posts en la base de datos.
Luego, añade un nuevo campo summary al modelo Post:
- summary:
CharField, máximo 500 caracteres, puede ser nulo.
Realiza nuevamente las migraciones necesarias para aplicar los cambios.
Solución
- Crear la app
posts:
python manage.py startapp posts
- Definir el modelo
Postenposts/models.py:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
- Crear y aplicar las migraciones:
python manage.py makemigrations posts
python manage.py migrate
- Añadir el campo
summaryal modeloPost:
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
summary = models.CharField(max_length=500, null=True)
def __str__(self):
return self.title
- Crear y aplicar las migraciones nuevamente:
python manage.py makemigrations posts
python manage.py migrate
Entrar en la base de datos y comprobar que la tabla posts se ha creado correctamente con todos los campos, incluido el nuevo campo summary.