Modelos

Para entender este tema crearemos un sistema de gestión de inventario de productos. Para ello, crearemos una clase Producto que representará un producto en el inventario. Cada producto tendrá un nombre, un precio y una cantidad en inventario.

Empezaremos creando un entorno virtual e instalando Django.

python -m venv env

Ahora activaremos el entorno virtual.

source env/bin/activate

crearemos un directorio llamado inventario y nos moveremos a ese directorio.

mkdir inventario
cd inventario

Una vez activado el entorno y creando el directorio inventario, instalaremos Django.

pip install django==4.2.0
Tip

Tip: Para crear un proyecto de Django, utilizamos el comando django-admin startproject. En este caso utilizamos la versión LTS, recuerda que puedes consultar la versión más reciente en la página oficial de Django. Sin embargo en este caso utilizaremos la versión 4.2.0.

Ahora crearemos un proyecto de Django llamado inventario

django-admin startproject inventario .

Luego crearemos una aplicación llamada productos

python manage.py startapp productos

Info: En Django, un proyecto es un conjunto de aplicaciones web y un proyecto puede contener múltiples aplicaciones.

Para que la app productos funcione, debemos registrarla en el archivo settings.py del proyecto inventario.

INSTALLED_APPS = [
    ...
    "productos",
]

Ahora crearemos la clase Producto en el archivo models.py de la aplicación productos.

from django.db import models

class Producto(models.Model):
    nombre = models.CharField(max_length=100)
    precio = models.DecimalField(max_digits=10, decimal_places=2)
    cantidad = models.IntegerField()

    def __str__(self):
        return self.nombre
Tip

Tip: La función __str__ es una función especial que se llama cuando se convierte un objeto a una cadena de texto.

Los modelos en Django son clases que representan tablas en la base de datos. Cada atributo de la clase representa una columna en la tabla y cada instancia de la clase representa una fila en la tabla.

Registramos la aplicacion en admin.py

Para que Django reconozca la clase Producto, debemos registrarla en el archivo admin.py de la aplicación productos.

from django.contrib import admin
1from .models import Producto

2admin.site.register(Producto)
1
Importamos la clase Producto.
2
Registramos la clase Producto en el panel de administración de Django.

Vistas en Django

Ahora crearemos las vistas de nuestro sistema en Django. Para ello, crearemos una función para cada vista que renderizará una plantilla HTML. Por lo tanto nuestras vistas están basadas en funciones. Sin embargo tambien existen vistas basadas en clases.

Tip

En Django, una vista es una función que recibe una petición HTTP y devuelve una respuesta HTTP.

Tip

¿Qué es un CRUD?

Un CRUD es un acrónimo que significa Crear, Leer, Actualizar y Eliminar. Es un conjunto de operaciones básicas que se pueden realizar en una base de datos o en un sistema de gestión de datos.

Listar productos

Para listar los productos en inventario, crearemos una función listar_productos que renderizará la plantilla listar.html con la lista de productos.

from pyexpat.errors import messages
from django.shortcuts import render, redirect, get_object_or_404
from .models import Producto
from django.urls import reverse 

productos = []

def listar_productos(request):
    productos = Producto.objects.all()
    return render(request, 'listar.html', {'productos': productos})

Agregar producto

Para agregar un producto al inventario, crearemos una función agregar_producto que recibe los datos del producto a agregar y lo agrega a la lista de productos.

def agregar_producto(request):
    if request.method == "POST":
        nombre = request.POST.get("nombre")
        precio = request.POST.get("precio")
        cantidad = request.POST.get("cantidad")
        Producto.objects.create(nombre=nombre, precio=precio, cantidad=cantidad) 
        return redirect('productos:listar_productos')
    return render(request, "agregar.html")

Actualizar producto

Para actualizar un producto en el inventario, crearemos una función actualizar_producto que recibe los datos del producto a actualizar y actualiza el precio y la cantidad del producto.

def actualizar_producto(request, id):
    producto = get_object_or_404(Producto, pk=id)
    if request.method == 'POST':
        nombre = request.POST.get('nombre')
        precio = request.POST.get('precio')
        cantidad = request.POST.get('cantidad')
        
        # Actualiza los campos del producto
        producto.nombre = nombre
        producto.precio = precio
        producto.cantidad = cantidad
        producto.save()
        
        return redirect('productos:listar_productos')
    else:
        return render(request, 'actualizar.html', {'producto': producto})

Eliminar producto

Para eliminar un producto del inventario, crearemos una función eliminar_producto que recibe el nombre del producto a eliminar y lo elimina de la lista de productos.

def eliminar_producto(request):
    if request.method == "POST":
        nombre = request.POST.get("nombre")
        try:
            producto = Producto.objects.get(nombre=nombre)
            producto.delete()
        except Producto.DoesNotExist:
            pass
        
        return redirect('productos:listar_productos')
    return render(request, "eliminar.html")

Buscar producto

Para buscar un producto en el inventario, crearemos una función buscar_producto que recibe el nombre del producto a buscar y renderiza la plantilla buscar.html con el producto encontrado.

def buscar_producto(request):
    if request.method == "POST":
        nombre = request.POST.get("nombre")
        try:
            producto = Producto.objects.get(nombre=nombre)
            return render(request, "buscar.html", {"producto": producto})
        except Producto.DoesNotExist:
            return render(request, "buscar.html", {"producto": None})
    return render(request, "buscar.html")

Templates

Django utiliza un sistema de herencia de plantillas llamado Jinja2. Adicional a ello uilizaremos un framework de CSS llamado Bootstrap.

Tip

Jinja2 es un motor de plantillas para Python que se utiliza en Django para renderizar plantillas HTML.

Tip

Bootstrap es un framework de CSS que se utiliza para crear sitios web y aplicaciones web responsivos y móviles.

Para crear las plantillas de nuestro sistema, crearemos una carpeta llamada templates en el directorio de la aplicación productos.

Teniendo la siguiente estructura:

productos/
    migrations/
    templates/
        productos/
            base.html
            listar.html
            agregar.html
            actualizar.html
            eliminar.html
            buscar.html
    __init__.py
    admin.py
    apps.py
    models.py
    tests.py
    views.py

Base

Crearemos un archivo base.html que contendrá la estructura base de todas las páginas de nuestro sistema.

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        {% block title %}
        Inventario
        {% endblock %}
    </title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        {% block content %} 
        {% endblock %}
    </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>

Listar

Crearemos un archivo listar.html que contendrá la lista de productos en inventario.

{% extends "base.html" %}

{% block title %} Listar Productos {% endblock %}

{% block content%}
<h1>Listar Productos</h1>
<ul class="list-group">
    {% for producto in productos %}
    <li class="list-group-item"> 
        {{ producto.nombre }} - {{ producto.precio }} - {{ producto.cantidad }}
    </li>
    {% endfor %}
</ul>
{% endblock%}

Agregar

Crearemos un archivo agregar.html que contendrá un formulario para agregar un producto al inventario.

{% extends "base.html" %}

{% block title %}Agregar producto{% endblock %}

{% block content %}
<h1>Agregar producto</h1>

<form action="{% url 'productos:agregar_producto' %}" method="post">
    {% csrf_token %}
    <div class="mb-3">
        <label for="nombre" class="form-label">Nombre</label>
        <input type="text" class="form-control" id="nombre" name="nombre">
    </div>
    <div class="mb-3">
        <label for="precio" class="form-label">Precio</label>
        <input type="number" class="form-control" id="precio" name="precio">
    </div>
    <div class="mb-3">
        <label for="cantidad" class="form-label">Cantidad</label>
        <input type="number" class="form-control" id="cantidad" name="cantidad">
    </div>
    <button type="submit" class="btn btn-primary">Agregar</button>
</form>
{% endblock %}

Actualizar

Crearemos un archivo actualizar.html que contendrá un formulario para actualizar un producto en el inventario.

{% extends "base.html" %}

{% block title %}Actualizar producto{% endblock %}

{% block content %}
<h1>Actualizar producto</h1>
<form action="{% url 'productos:actualizar_producto' producto.id %}" method="post">
    {% csrf_token %}
    <input type="hidden" name="nombre" value="{{ producto.nombre }}">
    <input type="hidden" name="id" value="{{ producto.id }}"> {# Agregamos un campo oculto para el ID del producto #}
    <div class="mb-3">
        <label for="precio" class="form-label">Precio</label>
        <input type="number" class="form-control" id="precio" name="precio" value="{{ producto.precio }}">
    </div>
    <div class="mb-3">
        <label for="cantidad" class="form-label">Cantidad</label>
        <input type="number" class="form-control" id="cantidad" name="cantidad" value="{{ producto.cantidad }}">
    </div>
    <button type="submit" class="btn btn-primary">Actualizar</button>
</form>
{% endblock %}

Eliminar

Crearemos un archivo eliminar.html que contendrá un formulario para eliminar un producto del inventario.

{% extends "base.html" %}

{% block title %}Eliminar producto{% endblock %}

{% block content %}
<h1>Eliminar producto</h1>
<form action="{% url 'productos:eliminar_producto' %}" method="post">
    {% csrf_token %}  <!-- Agrega el token CSRF aquí -->
    <div class="mb-3">
        <label for="nombre" class="form-label">Nombre</label>
        <input type="text" class="form-control" id="nombre" name="nombre">
    </div>
    <button type="submit" class="btn btn-primary">Eliminar</button>
</form>
{% endblock %}

Buscar

Crearemos un archivo buscar.html que contendrá un formulario para buscar un producto en el inventario.

{% extends "base.html" %}

{% block title %}Buscar producto{% endblock %}

{% block content %}
<h1>Buscar producto</h1>
<form action="{% url 'productos:buscar_producto' %}" method="post">
    {% csrf_token %}
    <div class="mb-3">
        <label for="nombre" class="form-label">Nombre</label>
        <input type="text" class="form-control" id="nombre" name="nombre">
    </div>
    <button type="submit" class="btn btn-primary">Buscar</button>
</form>

{% if producto %}
<div class="mt-3">
    <h2>Información del producto:</h2>
    <p>Nombre: {{ producto.nombre }}</p>
    <p>Precio: {{ producto.precio }}</p>
    <p>Cantidad: {{ producto.cantidad }}</p>
</div>
{% endif %}
{% endblock %}

URLs

Para que nuestro sistema funcione, necesitamos definir las URLs que se utilizarán para acceder a las diferentes vistas.

URLs en la aplicación y el proyecto

En el archivo urls.py de la aplicación productos definiremos las URLs de las vistas de nuestro sistema.

from django.urls import path
from . import views

app_name = 'productos'

urlpatterns = [
    path('', views.listar_productos, name='listar_productos'),
    path('agregar/', views.agregar_producto, name='agregar_producto'),
    path('actualizar/<int:id>/', views.actualizar_producto, name='actualizar_producto'),
    path('eliminar/', views.eliminar_producto, name='eliminar_producto'),
    path('buscar/', views.buscar_producto, name='buscar_producto'),
]

En el archivo urls.py del proyecto inventario incluiremos las URLs de la aplicación productos.

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('productos.urls')),
]
Tip

Tip: Para acceder al panel de administración de Django, debemos crear un superusuario con el siguiente comando.

python manage.py createsuperuser
Tip

Si realizamos modificaciones en el modelo de datos, debemos aplicar las migraciones con el siguiente comando.

1python manage.py makemigrations
2python manage.py migrate
1
Crea las migraciones.
2
Aplica las migraciones.
Tip

Tip: Para acceder a las vistas de nuestro sistema, debemos definir las URLs en el archivo urls.py de la aplicación y el proyecto.

En Django, las URLs se definen en el archivo urls.py de la aplicación y el proyecto. Las URLs se utilizan para acceder a las vistas de nuestro sistema.

Es necesario realizar una modificación en el archivo settings.py del proyecto inventario para que Django pueda encontrar las plantillas de nuestro sistema.

TEMPLATES = [
    {
        ...
1        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ...
    },
]
1
Agregamos la ruta de la carpeta templates al directorio de plantillas.

Ejecutar el servidor

Para ejecutar el servidor de desarrollo de Django, utilizaremos el siguiente comando.

python manage.py runserver

Con esto hemos creado un sistema de gestión de inventario de productos con Django. Ahora podemos listar, agregar, actualizar, eliminar y buscar productos en el inventario y hemos utilizado el sistema de plantillas de Django para crear las vistas de nuestro sistema. Adicional a ello tambien hemos utilizado el framework de CSS Bootstrap para darle estilo a nuestro sistema.

Conclusiones

En este tema hemos aprendido a crear un sistema de gestión de inventario de productos con Django. Hemos creado un modelo de datos para representar los productos en el inventario y hemos creado vistas para listar, agregar, actualizar, eliminar y buscar productos en el inventario. Adicional a ello tambien hemos creado plantillas HTML para renderizar las vistas de nuestro sistema.