Crear un blog con Django. Parte 2: Modelos (Models)
Para la segunda parte de este tutorial vamos a crear los modelos. El modelo se encarga de los datos, normalmente de las consultas, actualizaciones, etc. de una tabla en una base de datos.
User
Lo primero que vamos a hacer es crear el modelo para los usuarios. Django tiene su propio sistema de autenticación y modelo para usuarios así que lo utilizaremos para customizar nuestra propia clase de usuarios y posteriormente hacer el sistema de login. Si quieres más información puedes verla desde la documentación oficial de Django.
Para crear el módulo de usuarios lo que tenemos que hacer es lanzar el siguiente comando:
python manage.py startapp users
Esto nos generará la siguiente estructura de archivos en nuestro proyecto:
users/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
A parte de estos archivos en la raiz también nos ha creado un archivo llamado db.sqlite3. Esto es porque por defecto en simple_blog/settings.py tenemos configurada la base de datos de sqlite pero para producción os recomendaría que utilizaseis cualquier de las otras opciones que permite django que es postgresql, mysql y oracle.
Después de estos pasos vamos a meternos ya con el meollo. En nuestro archivo users/models.py añadimos las siguientes líneas:
"""Users models."""
# Django
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
"""Profile model.
Proxy model that extends the base data with other
information.
"""
user = models.OneToOneField(User, on_delete=models.PROTECT)
website = models.URLField(max_length=200, blank=True)
photo = models.ImageField(
upload_to='users/pictures',
blank=True,
null=True
)
date_modified = models.DateTimeField(auto_now=True)
def __str__(self):
"""Return username."""
return self.user.username
Aquí lo que estamos haciendo es importar la clase User de Django, que ya nos provee de varios campos para nuestra tabla, si quieres consultar que campos se pueden utilizar podéis verlo en la documentación.
Lo siguiente que hacemos en nuestra clase Profile es relacionar la clase User con nuestra clase uno a uno y añadiremos la opción on_delete=models.PROTECT que lo que hará es que no se puedan borrar los usuarios, esto lo haremos porque tenemos la opción de desactivar los usuarios y ya que los usuarios están relacionados con varías tablas el eliminar usuarios podría eliminar información importante relacionada con ellos.
Lo siguiente que haremos será customizar la clase y añadir nuestros propios campos, para este proyecto vamos ha añadir la opción de que el usuario pueda guardar su website, añadir una foto y la fecha de modificación del usuario.
Por último añadiremos el método __str__ y retornaremos el nombre de usuario, esto se utiliza para que cuando hagamos un print de un objecto user nos muestre el username, lo que nos dará más información del objecto a simple vista. Con esto ya tendremos finalizado el modelo para los usuarios.
Post
Ahora nos vamos a meter con el modelo para post, al igual que con usuarios creamos el módulo para los posts y para los comentarios y categorías ya que los necesitaremos:
python manage.py startapp posts
python manage.py startapp categories
python manage.py startapp comments
Y añadimos el siguiente código en posts/models.py:
"""Posts models."""
# Django
from django.db import models
from django.utils.text import slugify
from django.contrib.auth.models import User
from ckeditor.fields import RichTextField
from categories.models import Category
class Post(models.Model):
"""Post model."""
user = models.ForeignKey(User, on_delete=models.PROTECT)
profile = models.ForeignKey('users.Profile', on_delete=models.PROTECT)
title = models.CharField(max_length=255)
image_header = models.ImageField(upload_to='posts/photos')
post = RichTextField()
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
is_draft = models.BooleanField(default=True)
url = models.SlugField(max_length=255, unique=True)
views = models.PositiveIntegerField(default=0)
categories = models.ManyToManyField(Category)
class Meta:
ordering = ('title',)
def __str__(self):
"""Return title and username."""
return '{} by @{}'.format(self.title, self.user.username)
def save(self, *args, **kwargs):
self.url = slugify(self.title)
super(Post, self).save(*args, **kwargs)
Para este modelo estamos importando slugify en que ya explico en este tutorial sobre como crear urls amigables con slug en Django, la clase User ya que un post será creado por un usuario y el tipo de dato RichTextField que es un campo que viene de la librería que importamos en la parte 1.
Lo siguiente que haremos será crear la clase Post y relacionar los usuarios con los posts con la función ForeignKey, será una relación 1 a N ya que un usuario puede crear varios posts y un post pertenece a un único usuario. Como en el modelo de usuarios utilizaremos PROTECT ya que no queremos perder los posts.
Ahora describiremos los demás campos:
title: De tipo CharField y un tamaño máximo de 255 caracteres.
image_header: Será la cabecera de nuestro post y lo guardaremos en media/posts/photos.
post: Será de tipo RichTextField que nos permitirá crear textos con distintos tamaños, tipos de letra, colores, etc.
date_created: Fecha de creación. Se guardará la fecha actual por defecto por el atributo auto_now_add en la creación.
date_modified: Fecha de modificación. Se guardará la fecha actual por defecto cada vez que se actualice el post por el atributo auto_now.
is_draft: Un campo de tipo booleano, guardaremos si es un borrador o lo queremos mostrar en la web.
url: De tipo slugField, aquí guardaremos la url, se creará a partir del título.
views: Número de visitas.
categories: El listado de categorías asignadas a un post, es una relación de tipo N a N ya que un post puede tener varias categorías y una categoría puede pertenecer a varios posts.
Después declaramos la clase Meta y añadiremos el orden por título, esto hará que cuando retornemos una lista de objetos de tipo post, por defecto lo ordenará por posts.
El método __str__ que ya lo explicamos anteriormente.
El método save. Aquí lo que hacemos es que cuando se va a guardar el Post pasamos la función slugify sobre el título y lo guardamos en el campo url.
Categories
Este será muy sencillo simplemente tendrá un campo name. Añadiremos el siguiente código:
"""Categories"""
from django.db import models
# Models
# Create your models here.
class Category(models.Model):
"""Category model."""
name = models.CharField(max_length=100,unique=True)
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
Comments
Por último crearemos el modelo para los comentarios, contendrá el siguiente código:
"""Comments"""
from django.db import models
from django.contrib.auth.models import User
from posts.models import Post
# Model
# Create your models here.
class Comment(models.Model):
"""Comment model."""
user = models.ForeignKey(User, on_delete=models.PROTECT)
profile = models.ForeignKey('users.Profile', on_delete=models.PROTECT)
post = models.ForeignKey(Post, on_delete=models.PROTECT)
comment = models.CharField(max_length=5000)
def __str__(self):
return self.comment
Aquí lo que hemos hecho es añadir las relaciones con el usuario y el post que será 1 a N para ambos casos, ya que un comentario pertenece a un usuario y a un post y un usuario y un post pueden tener varios comentarios. La clave foránea que relaciona los comentarios con post en el modelo de post lo que haría que cada vez que obtuviesemos un objecto de tipo post obtuviese todos los comentarios en dicho post pero si tenemos varios comentarios podría ralentizar nuestra web, haciéndolo de esta manera solo traemos los comentarios cuando los necesitemos.
Ahora lo que tenemos que hacer es editar nuestro archivo simple_blog/settings.py y lo modificaremos para añadir los siguientes módulos:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Rich text editor
'ckeditor',
# Local apps
'posts',
'users',
'categories',
'comments',
]
Una vez creado los modelos lanzamos el siguiente comando:
python manage.py makemigrations
python manage.py migrate
El primero genera un archivo para la creación/modificación de la tabla y el segundo creará las tablas en la base de datos.
Conclusiones
Si ya habéis trabajado con otros frameworks a la hora de crear modelos veréis que es siempre lo mismo, yo que he probado varios frameworks diría que el de Django es el más sencillo hasta la fecha, si tienes una opinión diferente te ánimo que lo pongas en los comentarios :)
Con esto ya tenemos creados los modelos, en la siguiente parte nos meteremos en la parte de la administración del blog.
Espero que este post te ayude y como siempre, te recomiendo seguirme en Twitter para estar al tanto de los nuevo contenido. Ahora también puedes seguirme en Instagram donde estoy subiendo tips, tutoriales en vídeo e información sobre herramientas para developers.
Por último os dejo mi guía para aprender a trabajar con APIs donde explico todo el funcionamiento de una API, el protocolo HTTP y veremos como construir una API con arquitectura REST.
Nos leemos 👋.