Tutorial paso a paso para crear una aplicación web de notas con Django y Bootstrap
Crear una aplicación web para gestionar notas es un proyecto ideal para desarrolladores principiantes e intermedios que quieren aprender desarrollo web con Python usando Django y mejorar la interfaz con Bootstrap. En este tutorial detallado, aprenderás a configurar tu entorno, crear modelos, vistas y URLs para implementar operaciones CRUD (Crear, Leer, Actualizar, Eliminar), manejar formularios con validación y desplegar tu app básica.
Este tutorial Django notas te guiará paso a paso para que puedas crear una app funcional, responsive y lista para crecer.
Contenidos
- 1. Configuración del entorno y creación del proyecto Django
- 2. Creación del modelo Nota
- 3. Desarrollo de vistas y URLs para operaciones CRUD
- 4. Integración de plantillas HTML con Bootstrap
- 5. Manejo de formularios y validaciones
- 6. Despliegue básico de la aplicación
- Conclusión y buenas prácticas
1. Configuración del entorno y creación del proyecto Django
a) Instalación y configuración del entorno virtual
Recomendamos usar un entorno virtual para gestionar las dependencias:
1 2 3 4 5 6 7 8 |
# Crear y activar entorno virtual (en Linux/MacOS) python3 -m venv env source env/bin/activate # En Windows python -m venv env env\Scripts\activate |
b) Instalación de Django
Con el entorno activo:
1 2 |
pip install django |
Verifica la instalación:
1 2 |
django-admin --version |
c) Crear el proyecto Django
Genera un nuevo proyecto llamado notas_project
:
1 2 3 |
django-admin startproject notas_project cd notas_project |
d) Crear la aplicación para gestionar notas
1 2 |
python manage.py startapp notas |
e) Registrar la app en el proyecto
Edita notas_project/settings.py
para añadir 'notas'
en INSTALLED_APPS
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
INSTALLED_APPS = [ # apps django por defecto 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # nuestra app 'notas', ] |
f) Ejecutar la migración inicial
1 2 |
python manage.py migrate |
Con esto ya tienes tu proyecto Django y app notas preparados para comenzar el desarrollo.
2. Creación del modelo Nota
Vamos a definir el modelo que representará cada nota.
El archivo a modificar:
notas/models.py
1 2 3 4 5 6 7 8 9 10 11 |
from django.db import models class Nota(models.Model): titulo = models.CharField(max_length=200) contenido = models.TextField() fecha_creacion = models.DateTimeField(auto_now_add=True) fecha_modificacion = models.DateTimeField(auto_now=True) def __str__(self): return self.titulo |
Explicación:
titulo
: texto corto para el título de la nota.contenido
: texto extenso para la descripción.fecha_creacion
: fecha y hora automáticas cuando la nota se crea.fecha_modificacion
: fecha y hora automáticas cuando la nota se actualiza.
Ahora, crea y aplica migraciones:
1 2 3 |
python manage.py makemigrations notas python manage.py migrate |
3. Desarrollo de vistas y URLs para operaciones CRUD
Vamos a implementar las vistas que gestionan la creación, listado, actualización y eliminación de notas.
a) Crear vistas en notas/views.py
Usaremos vistas basadas en funciones para facilidad y claridad.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
from django.shortcuts import render, get_object_or_404, redirect from .models import Nota from .forms import NotaForm # Listar todas las notas def listar_notas(request): notas = Nota.objects.all().order_by('-fecha_creacion') return render(request, 'notas/lista.html', {'notas': notas}) # Crear nueva nota def crear_nota(request): if request.method == 'POST': form = NotaForm(request.POST) if form.is_valid(): form.save() return redirect('listar_notas') else: form = NotaForm() return render(request, 'notas/formulario.html', {'form': form, 'accion': 'Crear'}) # Editar nota existente def editar_nota(request, pk): nota = get_object_or_404(Nota, pk=pk) if request.method == 'POST': form = NotaForm(request.POST, instance=nota) if form.is_valid(): form.save() return redirect('listar_notas') else: form = NotaForm(instance=nota) return render(request, 'notas/formulario.html', {'form': form, 'accion': 'Editar'}) # Eliminar nota def eliminar_nota(request, pk): nota = get_object_or_404(Nota, pk=pk) if request.method == 'POST': nota.delete() return redirect('listar_notas') return render(request, 'notas/eliminar_confirmar.html', {'nota': nota}) |
b) Crear URLs para estas vistas en notas/urls.py
Primero crea un archivo urls.py
dentro de la carpeta notas
:
1 2 3 4 5 6 7 8 9 10 |
from django.urls import path from . import views urlpatterns = [ path('', views.listar_notas, name='listar_notas'), path('crear/', views.crear_nota, name='crear_nota'), path('editar/<int:pk>/', views.editar_nota, name='editar_nota'), path('eliminar/<int:pk>/', views.eliminar_nota, name='eliminar_nota'), ] |
c) Conectar URLs de la app al proyecto principal
En notas_project/urls.py
modifica así:
1 2 3 4 5 6 7 8 |
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('notas.urls')), # conecta la app notas ] |
4. Integración de plantillas HTML con Bootstrap
Bootstrap nos permite crear interfaces responsive atractivas con poco esfuerzo.
a) Estructura de carpetas para plantillas
En la carpeta notas
, crea:
1 2 |
notas/templates/notas/ |
Vamos a colocar aquí las siguientes plantillas:
base.html
lista.html
formulario.html
eliminar_confirmar.html
b) Plantilla base base.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>App Notas Django + Bootstrap</title> <!-- Bootstrap CSS desde CDN --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-4"> <div class="container"> <a class="navbar-brand" href="{% url 'listar_notas' %}">Mis Notas</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"> <span class="navbar-toggler-icon"></span> </button> </div> </nav> <main class="container"> {% block content %}{% endblock %} </main> <!-- Bootstrap JS bundle --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> </body> </html> |
c) Listado de notas: lista.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
{% extends 'notas/base.html' %} {% block content %} <h1 class="mb-4">Lista de Notas</h1> <a href="{% url 'crear_nota' %}" class="btn btn-success mb-3">+ Nueva Nota</a> {% if notas %} <table class="table table-striped"> <thead> <tr> <th>Título</th> <th>Creada</th> <th>Modificada</th> <th>Acciones</th> </tr> </thead> <tbody> {% for nota in notas %} <tr> <td>{{ nota.titulo }}</td> <td>{{ nota.fecha_creacion|date:'d/m/Y H:i' }}</td> <td>{{ nota.fecha_modificacion|date:'d/m/Y H:i' }}</td> <td> <a href="{% url 'editar_nota' nota.pk %}" class="btn btn-primary btn-sm">Editar</a> <a href="{% url 'eliminar_nota' nota.pk %}" class="btn btn-danger btn-sm">Eliminar</a> </td> </tr> {% endfor %} </tbody> </table> {% else %} <p>No hay notas registradas.</p> {% endif %} {% endblock %} |
d) Formulario para crear/editar nota: formulario.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{% extends 'notas/base.html' %} {% block content %} <h1>{{ accion }} Nota</h1> <form method="post" novalidate> {% csrf_token %} <div class="mb-3"> <label for="id_titulo" class="form-label">Título</label> {{ form.titulo|as_widget(attrs={'class':'form-control', 'placeholder':'Título de la nota'}) }} {% if form.titulo.errors %} <div class="text-danger">{{ form.titulo.errors }}</div> {% endif %} </div> <div class="mb-3"> <label for="id_contenido" class="form-label">Contenido</label> {{ form.contenido|as_widget(attrs={'class':'form-control', 'rows':'6', 'placeholder':'Contenido de la nota'}) }} {% if form.contenido.errors %} <div class="text-danger">{{ form.contenido.errors }}</div> {% endif %} </div> <button type="submit" class="btn btn-primary">Guardar</button> <a href="{% url 'listar_notas' %}" class="btn btn-secondary">Cancelar</a> </form> {% endblock %} |
e) Confirmación para eliminar: eliminar_confirmar.html
1 2 3 4 5 6 7 8 9 10 11 12 |
{% extends 'notas/base.html' %} {% block content %} <h1>Eliminar Nota</h1> <p>¿Estás seguro de que deseas eliminar la nota "<strong>{{ nota.titulo }}</strong>"?</p> <form method="post"> {% csrf_token %} <button type="submit" class="btn btn-danger">Eliminar</button> <a href="{% url 'listar_notas' %}" class="btn btn-secondary">Cancelar</a> </form> {% endblock %} |
5. Manejo de formularios y validaciones
Django facilita el manejo de formularios con su módulo forms
.
a) Crear el formulario en notas/forms.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from django import forms from .models import Nota class NotaForm(forms.ModelForm): class Meta: model = Nota fields = ['titulo', 'contenido'] widgets = { 'titulo': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Título de la nota'}), 'contenido': forms.Textarea(attrs={'class': 'form-control', 'rows': 6, 'placeholder': 'Contenido de la nota'}), } def clean_titulo(self): titulo = self.cleaned_data.get('titulo') if not titulo: raise forms.ValidationError('El título no puede estar vacío.') return titulo def clean_contenido(self): contenido = self.cleaned_data.get('contenido') if not contenido: raise forms.ValidationError('El contenido no puede estar vacío.') return contenido |
b) Uso en vistas
Como viste en la sección vistas, usamos este formulario para obtener datos, validar y guardar la nota.
Explicación
- El formulario hereda de
ModelForm
simplificando la creación con base al modelo. - Se usan
clean_*
para validar campos específicos. - Los widgets aseguran que el formulario tenga estilos Bootstrap.
6. Despliegue básico de la aplicación
Para desplegar localmente o en servidor básico, asegúrate de:
a) Configurar archivos estáticos para producción (opcional)
Añadir en settings.py
:
1 2 3 4 5 |
import os STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') |
Luego ejecuta:
1 2 |
python manage.py collectstatic |
b) Ejecutar el servidor localmente
1 2 |
python manage.py runserver |
Abre en tu navegador http://127.0.0.1:8000/ y verás tu aplicación de notas en acción.
c) Próximos pasos para despliegue real
Para producción puedes optar por plataformas como Heroku, AWS, DigitalOcean o utilizar Docker.
Algunos recursos para desplegar apps Django:
- Configurar base de datos como PostgreSQL
- Usar servidor WSGI como Gunicorn
- Servir archivos estáticos con Nginx
Esto excede el alcance pero es un buen punto de partida.
Conclusión y buenas prácticas
En este tutorial aprendiste a crear una aplicación CRUD Django para gestionar notas, integrando una interfaz responsive con Bootstrap. Cubrimos desde la configuración inicial, creación de modelos, rutas, manejo de formularios y validaciones, hasta un despliegue básico.
Buenas prácticas a tener en cuenta:
- Usa entornos virtuales para gestionar dependencias.
- Mantén la lógica de negocio separada en vistas y modelos.
- Utiliza plantillas base para evitar duplicidad de código HTML.
- Valida los datos del formulario tanto en frontend (idealmente) como backend.
- Controla bien las URLs y nombres de rutas para facilitar mantenimiento.
- Prueba tu app localmente antes de desplegar.
¡Manos a la obra!
Empieza ya a crear tu app Django Bootstrap para gestionar notas y aprovecha todo el potencial de Django para el desarrollo web Python.
Puedes ampliar esta app incorporando autenticación de usuarios, búsqueda, paginación y mucho más.
Si te ha gustado este tutorial Django notas, compártelo y suscríbete para más contenido práctico y didáctico.