Introducción
En este tutorial, crearemos modelos de Django que definen los campos y comportamientos de los datos de la aplicación de blog que almacenaremos. Estos modelos asignan los datos de la aplicación de Django a la base de datos. Esto es lo que Django utiliza para generar tablas de base de datos mediante la API de Mapeo Relacional de Objetos (ORM), llamadas "modelos".
Requisitos previos
Este tutorial es parte de la serie Desarrollo Django y es una continuación de esa serie.
Si no ha estado siguiendo esta serie, hacemos las siguientes suposiciones:
- Ha instalado Django versión 4 o superior.
- Ha conectado su aplicación Django a una base de datos.
- Estás trabajando con un sistema operativo basado en Unix, preferiblemente un servidor en nube Ubuntu 22.04, ya que este es el sistema en el que hemos realizado pruebas.
Dado que este tutorial trata principalmente sobre modelos de Django, es posible que puedas seguirlo incluso si tienes una configuración diferente.
Paso 1 – Crear la aplicación Django
Para mantener la filosofía modular de Django, crearemos una aplicación Django en nuestro proyecto que contenga todos los archivos necesarios para crear el sitio web del blog.
Al empezar a trabajar con Python y Django, debemos activar nuestro entorno virtual de Python y moverlo al directorio raíz de nuestra aplicación. Si seguiste la serie, puedes lograrlo escribiendo lo siguiente.
cd ~/my_blog_app
. env/bin/activate
cd blogr code... */Desde allí, ejecutemos este comando:
python manage.py startapp blogsiteEste programa crea nuestro sitio de blog junto con un directorio.
En este punto de la serie de tutoriales, tendrá la siguiente estructura de directorio para su proyecto:
my_blog_app/
└── blog
├── blog
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-38.pyc
│ │ ├── settings.cpython-38.pyc
│ │ ├── urls.cpython-38.pyc
│ │ └── wsgi.cpython-38.pyc
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── blogsite
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.pyEl archivo en el que nos centraremos para este tutorial será el archivo models.py, que se encuentra en el directorio del blog del sitio.
Paso 2: Agregar plantillas de publicaciones
Primero, necesitamos abrir y editar el archivo models.py para que contenga el código que generará un modelo de publicación. Un modelo de publicación contiene los siguientes campos de base de datos:
- TÍTULO – El título de la publicación del blog.
- Slug: donde se almacenan y generan URL válidas para páginas web.
- CONTENIDO – El contenido textual de la publicación del blog.
- create_on – La fecha en que se creó la publicación.
- AUTOR – La persona que escribió la publicación.
Ahora vaya al directorio donde se encuentra el archivo models.py.
cd ~/my_blog_app/blog/blogsiteUtilice el comando cat para mostrar el contenido del archivo en su terminal.
cat models.pyEl archivo debe contener el siguiente código que importa los modelos, junto con un comentario que explique qué incluye este archivo models.py.
from django.db import models
# Create your models here.Con tu editor de texto favorito, añade el siguiente código al archivo models.py. Usaremos nano como editor de texto, pero puedes usar el que prefieras.
nano models.pyEn este archivo, ya se agregó el código para importar los modelos de API; podemos eliminar el comentario a continuación. Luego, importamos slugify para generar slugs a partir de cadenas, el usuario de Django para la autenticación y el proceso inverso desde django.urls para mayor flexibilidad al crear URL.
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverseA continuación, agregue un método de clase con los siguientes campos de base de datos: título, slug, contenido, created_on y autor, en la clase modelo que llamaremos Post. Añádalos debajo de las declaraciones de importación.
...
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()A continuación, añadimos una función para generar la URL y otra para guardar la publicación. Esto es muy importante, ya que crea un enlace único que coincide con nuestra publicación.
...
def get_absolute_url(self):
return reverse('blog_post_detail', args=[self.slug])
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)Ahora necesitamos indicarle al modelo cómo deben ordenarse y mostrarse las publicaciones en la página web. La lógica para esto se añadirá a una metaclase anidada. La metaclase generalmente contiene otra lógica importante del modelo que no está relacionada con la definición del campo de la base de datos.
...
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.titleFinalmente, añadimos el modelo Comment a este archivo. Esto implica añadir otra clase llamada Comment con models.Models en su firma y definir los siguientes campos de la base de datos:
- NOMBRE – El nombre de la persona que envía el comentario.
- CORREO ELECTRÓNICO – La dirección de correo electrónico de la persona que envía el comentario.
- TEXTO – El texto del comentario en sí.
- POST – La publicación con la que se realizó el comentario.
- create_on – Cuando se creó el comentario.
...
class Comment(models.Model):
name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)En este punto, models.py estará completo. Asegúrate de que tu archivo models.py coincida con lo siguiente:
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()
def get_absolute_url(self):
return reverse('blog_post_detail', args=[self.slug])
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
class Comment(models.Model):
name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)Asegúrate de guardar y cerrar el archivo. Si usas nano, puedes hacerlo presionando Ctrl y X, luego Y y luego Enter.
Con el archivo models.py en ejecución, podemos actualizar nuestro archivo settings.py.
Paso 3 – Actualizar la configuración
Ahora que hemos añadido modelos a nuestra aplicación, necesitamos informar a nuestro proyecto sobre la existencia de la aplicación de blog que acabamos de añadir. Para ello, la añadimos a la sección INSTALLED_APPS de settings.py.
Vaya al directorio donde se encuentra su settings.py.
cd ~/my_blog_app/blog/blogDesde aquí, abra su archivo settings.py con nano, por ejemplo.
nano settings.pyAl abrir el archivo, agregue la aplicación de blog de su sitio a la sección INSTALLED_APPS del archivo, como se muestra a continuación.
# Application definition
INSTALLED_APPS = [
'blogsite',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]Con la aplicación de blog del sitio agregada, puede guardar el archivo y salir.
En este punto, estamos listos para avanzar con la implementación de estos cambios.
Paso 4 – Realizar la migración
Con los modelos Post y Comment agregados, el siguiente paso es aplicar estos cambios para que nuestro esquema de base de datos MySQL los reconozca y cree las tablas necesarias.
Primero, necesitamos empaquetar los cambios de nuestro modelo en archivos de migración separados mediante el comando makemigrations. Estos archivos son similares a las confirmaciones en un sistema de control de versiones como Git.
Ahora, si vas a ~/my_blog_app/blog/blogsite/migrations y ejecutas ls, notarás que solo hay un archivo __init__.py. Esto cambiará cuando agreguemos migraciones.
Cambie al directorio del blog usando cd, de la siguiente manera:
cd ~/my_blog_app/blogLuego, ejecute el comando makemigrations en manager.py.
python manage.py makemigrationsLuego deberías obtener el siguiente resultado en tu ventana de terminal:
Output
Migrations for 'blogsite':
blogsite/migrations/0001_initial.py
- Create model Post
- Create model Comment
¿Recuerdas cuando fuimos a /~/my_blog_app/blog/blogsite/migrations y solo tenía el archivo __init__.py? Si volvemos a ese directorio, veremos que se han añadido dos elementos más: __pycache__ y 0001_initial.py. El archivo 0001_initial.py se creó automáticamente al ejecutar makemigrations. Se creará un archivo similar cada vez que ejecutes makemigrations.
Si desea leer el contenido del archivo, simplemente ejecute 0001_initial.py desde el directorio en el que se encuentra.
Ahora ve a ~/my_blog_app/blog:
cd ~/my_blog_app/blogDado que hemos creado un archivo de migración, necesitamos aplicar los cambios que estos archivos describen a la base de datos mediante el comando "migrar". Pero primero, verifiquemos qué migraciones existen actualmente con el comando "showmigrations".
python manage.py showmigrationsOutput
admin
[X] 0001_initial
[X] 0002_logentry_remove_auto_add
[X] 0003_logentry_add_action_flag_choices
auth
[X] 0001_initial
[X] 0002_alter_permission_name_max_length
[X] 0003_alter_user_email_max_length
[X] 0004_alter_user_username_opts
[X] 0005_alter_user_last_login_null
[X] 0006_require_contenttypes_0002
[X] 0007_alter_validators_add_error_messages
[X] 0008_alter_user_username_max_length
[X] 0009_alter_user_last_name_max_length
[X] 0010_alter_group_name_max_length
[X] 0011_update_proxy_permissions
blogsite
[ ] 0001_initial
contenttypes
[X] 0001_initial
[X] 0002_remove_content_type_name
sessions
[X] 0001_initialNotarás que todas las migraciones están marcadas, excepto la de 0001_initial que creamos con los modelos Publicación y Comentario.
Ahora, verifiquemos qué sentencias SQL se ejecutan tras las migraciones con el siguiente comando. Este utiliza la migración y su título como argumento:
python manage.py sqlmigrate blogsite 0001_initialA continuación se muestra la consulta SQL real que se realiza detrás de escena.
Output
--
-- Create model Post
--
CREATE TABLE `blogsite_post` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `title` varchar(255) NOT NULL, `slug` varchar(255) NOT NULL UNIQUE, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `author` longtext NOT NULL);
--
-- Create model Comment
--
CREATE TABLE `blogsite_comment` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(42) NOT NULL, `email` varchar(75) NOT NULL, `website` varchar(200) NULL, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `post_id` integer NOT NULL);
ALTER TABLE `blogsite_comment` ADD CONSTRAINT `blogsite_comment_post_id_de248bfe_fk_blogsite_post_id` FOREIGN KEY (`post_id`) REFERENCES `blogsite_post` (`id`);Ahora ejecutemos las migraciones para aplicarlas a nuestra base de datos MySQL.
python manage.py migrateObtendremos el siguiente resultado:
Output
Operations to perform:
Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
Applying blogsite.0001_initial... OKAhora has aplicado tus migraciones exitosamente.
Es importante tener en cuenta que, como se indica en la documentación de Django, hay tres salvedades a tener en cuenta al migrar Django con MySQL como backend.
- No se admiten transacciones relacionadas con operaciones de cambio de esquema. En otras palabras, si una migración falla, debe seleccionar manualmente los cambios realizados para realizar otra migración. No es posible volver a un punto anterior antes de realizar cambios en la migración fallida.
- Para la mayoría de las operaciones de cambio de esquema, MySQL reescribe completamente las tablas. En el peor de los casos, la complejidad temporal es proporcional al número de filas de la tabla para agregar o eliminar columnas. Según la documentación de Django, esto puede tardar hasta un minuto por millón de filas.
- En MySQL, existen límites pequeños en la longitud de los nombres de columnas, tablas e índices. También existe un límite en el tamaño combinado de todas las columnas y volúmenes de índice. Si bien otros backends admiten los límites más altos creados en Django, no se pueden crear los mismos índices con un backend MySQL.
Para cualquier base de datos que considere utilizar con Django, asegúrese de sopesar los pros y los contras de cada una.
Paso 5 – Verificar el esquema de la base de datos
Una vez completada la migración, necesitamos verificar la generación exitosa de las tablas MySQL que creamos a través de los modelos de Django.
Para hacer esto, ejecute el siguiente comando en la terminal para iniciar sesión en MySQL.
mysql blog_data -u djangouserAhora, seleccione nuestra base de datos blog_data. Si no sabe qué base de datos está usando, puede mostrar todas las bases de datos con SHOW DATABASES. En SQL
USE blog_data;Luego escriba el siguiente comando para ver las tablas.
SHOW TABLES;Esta consulta SQL debería revelar lo siguiente:
Output
+----------------------------+
| Tables_in_blog_data |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| blogsite_comment |
| blogsite_post |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
12 rows in set (0.01 sec)Las tablas incluyen blogsite_comment y blogsite_post. Son modelos que creamos nosotros mismos. Verifiquemos que contengan los campos que definimos.
DESCRIBE blogsite_comment;Output
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(42) | NO | | NULL | |
| email | varchar(75) | NO | | NULL | |
| website | varchar(200) | YES | | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| post_id | int | NO | MUL | NULL | |
+------------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)DESCRIBE blogsite_post;Output
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| slug | varchar(255) | NO | UNI | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| author | longtext | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)Hemos verificado que las tablas de la base de datos se han generado correctamente a partir de nuestras migraciones de modelos Django.
Puede cerrar MySQL con CTRL + D y cuando esté listo para salir de su entorno Python, puede ejecutar el comando deshabilitar:
deactivateAl deshabilitar el entorno de desarrollo, regresará a la línea de comandos de la terminal.
Resultado
En este tutorial, hemos añadido con éxito modelos para la funcionalidad básica de una aplicación web de blog. Ha aprendido a codificar los modelos, cómo funcionan las migraciones y el proceso de conversión de modelos de Django a tablas reales de bases de datos MySQL.









