W3docs

Tutorial de Django

Aprende Django desde cero: instala el framework, crea modelos, vistas, plantillas, ejecuta migraciones y lanza una app web funcional paso a paso.

Django es un framework web de alto nivel para Python que te permite crear aplicaciones web seguras y escalables de forma rápida. Sigue el patrón arquitectónico Model-Template-View (MTV) — un pariente cercano de MVC — e incluye un ORM, una interfaz de administración, enrutamiento de URL, autenticación y mucho más. La filosofía "batteries-included" de Django significa que puedes centrarte en la lógica de tu aplicación en lugar de ensamblar infraestructura.

Este tutorial recorre los pasos esenciales: instalar Django dentro de un entorno virtual, crear un proyecto y una app, definir modelos, escribir vistas, construir plantillas, ejecutar migraciones de base de datos y verificar todo en el navegador.

Por qué usar Django

Batteries Included

Django incluye un panel de administración integrado, autenticación de usuarios, manejo de formularios, un ORM, soporte de caché y utilidades de internacionalización. No es necesario buscar paquetes de terceros para cubrir estos aspectos básicos.

Seguridad por defecto

Django protege contra la inyección SQL usando consultas parametrizadas a través de su ORM. También ofrece protección integrada contra Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF) y clickjacking. La clave secreta, el modo DEBUG y la configuración ALLOWED_HOSTS reducen aún más la superficie de ataque.

Escalabilidad

Django impulsa sitios de alto tráfico como Instagram y Disqus. Su framework de caché se integra con Memcached y Redis, y el ORM soporta conexiones de base de datos en pool. Puedes escalar vertical u horizontalmente sin modificar el código de tu aplicación.

Gran ecosistema

El índice de paquetes de Django lista miles de apps de terceros — APIs REST (djangorestframework), manejo de imágenes, pasarelas de pago y más. La estabilidad del framework y su ciclo de versiones largo garantizan que estos paquetes se mantengan activamente.

Cómo funciona el patrón MTV de Django

CapaTérmino DjangoResponsabilidad
DatosModelClase Python que mapea a una tabla de base de datos
PresentaciónTemplateArchivo HTML con marcadores de posición {{ variable }}
LógicaViewFunción (o clase) Python que lee datos y devuelve una respuesta

El despachador de URL (urls.py) mapea las rutas de las solicitudes entrantes a la vista correcta. La vista consulta los modelos y luego pasa los datos a una plantilla. El HTML renderizado se devuelve al navegador.

Configurar un entorno virtual

Siempre aísla los proyectos Django en un entorno virtual para que las dependencias no entren en conflicto entre proyectos.

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate        # macOS / Linux
venv\Scripts\activate           # Windows

Tras la activación, el prompt muestra (venv). Cada pip install a partir de este punto afecta solo a este entorno.

Instalar Django

Con el entorno virtual activo, instala Django usando pip:

pip install django

Verifica la instalación:

python -m django --version

Django muestra una cadena de versión como 5.1.4.

Crear un proyecto Django

Un proyecto es el contenedor de nivel superior para todo tu sitio. Crea uno con:

django-admin startproject mysite
cd mysite

Esto genera la siguiente estructura:

mysite/
├── manage.py          # Command-line utility for this project
└── mysite/
    ├── __init__.py
    ├── settings.py    # Project configuration (database, installed apps, …)
    ├── urls.py        # Root URL dispatcher
    ├── asgi.py        # ASGI entry point
    └── wsgi.py        # WSGI entry point

manage.py es tu herramienta principal para ejecutar comandos como iniciar el servidor de desarrollo, crear migraciones y crear un superusuario. La carpeta interna mysite/ es el paquete Python del propio proyecto.

Crear una app Django

Un proyecto puede contener múltiples apps — módulos autocontenidos, cada uno responsable de un área de funcionalidad. Crea una app de blog:

python manage.py startapp blog

Regístrala para que Django pueda encontrar sus modelos, plantillas y archivos estáticos. Abre mysite/settings.py y añade 'blog' a INSTALLED_APPS:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',                   # <-- add this line
]

El directorio de la app tiene este aspecto después de la creación:

blog/
├── __init__.py
├── admin.py       # Register models with the admin interface
├── apps.py        # App configuration
├── migrations/    # Auto-generated migration files
│   └── __init__.py
├── models.py      # Database models
├── tests.py
└── views.py       # View functions

Definir modelos

Un modelo es una clase Python que hereda de django.db.models.Model. Cada atributo de clase se corresponde con una columna de la base de datos. El ORM de Django traduce tu código Python a SQL y gestiona todas las interacciones con la base de datos.

Abre blog/models.py y define un modelo Post:

from django.db import models
from django.contrib.auth.models import User

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    date_posted = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ['-date_posted']   # Newest posts first

Tipos de campo clave usados aquí:

CampoPropósito
CharField(max_length=N)Texto corto con una longitud máxima
TextField()Texto de longitud ilimitada
ForeignKey(…, on_delete=CASCADE)Relación muchos-a-uno; elimina las publicaciones cuando se elimina su autor
DateTimeField(auto_now_add=True)Se establece una sola vez cuando se crea el registro
DateTimeField(auto_now=True)Se actualiza cada vez que se guarda el registro

El método __str__ controla cómo se muestra el objeto en el panel de administración y en el shell de Python.

Ejecutar migraciones

Después de definir o modificar modelos debes crear y aplicar migraciones — instrucciones versionadas que actualizan el esquema de la base de datos.

# Generate a new migration file from your model changes
python manage.py makemigrations

# Apply all pending migrations to the database
python manage.py migrate

Verás una salida como esta:

Migrations for 'blog':
  blog/migrations/0001_initial.py
    - Create model Post

Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying blog.0001_initial... OK

Ejecuta migrate cada vez que añadas, elimines o modifiques campos de un modelo. Nunca edites los archivos de migración a mano a menos que entiendas completamente su SQL.

Usar el panel de administración de Django

La interfaz de administración integrada te permite crear, leer, actualizar y eliminar registros desde el navegador — sin necesidad de una interfaz personalizada. Registra el modelo Post en blog/admin.py:

from django.contrib import admin
from .models import Post

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'date_posted')
    list_filter = ('date_posted', 'author')
    search_fields = ('title', 'content')

Crea una cuenta de superusuario para poder iniciar sesión:

python manage.py createsuperuser

Django solicita un nombre de usuario, correo electrónico y contraseña. Luego inicia el servidor de desarrollo y visita http://127.0.0.1:8000/admin/:

python manage.py runserver

Inicia sesión con las credenciales del superusuario y verás el modelo Posts listado en la sección "Blog".

Escribir vistas

Una vista es una función (o clase) Python que recibe una solicitud HTTP y devuelve una respuesta HTTP. Abre blog/views.py:

from django.shortcuts import render, get_object_or_404
from .models import Post

def post_list(request):
    """Display all published posts, newest first."""
    posts = Post.objects.all()
    return render(request, 'blog/post_list.html', {'posts': posts})

def post_detail(request, pk):
    """Display a single post by primary key."""
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

get_object_or_404 es un atajo muy útil: obtiene el objeto de la base de datos o devuelve automáticamente una respuesta 404 si no existe. El tercer argumento de render es un diccionario de contexto — sus claves se convierten en variables de plantilla.

Crear plantillas

Las plantillas son archivos HTML que contienen etiquetas del Django Template Language (DTL). Crea la siguiente estructura de directorios:

blog/
└── templates/
    └── blog/
        ├── base.html
        ├── post_list.html
        └── post_detail.html

blog/templates/blog/base.html — una maquetación compartida:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}My Blog{% endblock %}</title>
</head>
<body>
    <header><h1>My Blog</h1></header>
    <main>
        {% block content %}{% endblock %}
    </main>
</body>
</html>

blog/templates/blog/post_list.html — la página de listado:

{% extends "blog/base.html" %}

{% block title %}All Posts{% endblock %}

{% block content %}
  {% for post in posts %}
    <article>
      <h2><a href="/blog/{{ post.pk }}/">{{ post.title }}</a></h2>
      <p>By {{ post.author }} on {{ post.date_posted|date:"N j, Y" }}</p>
      <p>{{ post.content|truncatewords:30 }}</p>
    </article>
  {% empty %}
    <p>No posts yet.</p>
  {% endfor %}
{% endblock %}

blog/templates/blog/post_detail.html — la página de detalle:

{% extends "blog/base.html" %}

{% block title %}{{ post.title }}{% endblock %}

{% block content %}
  <h2>{{ post.title }}</h2>
  <p>By {{ post.author }} on {{ post.date_posted|date:"N j, Y" }}</p>
  <div>{{ post.content }}</div>
  <a href="/">Back to all posts</a>
{% endblock %}

Características clave del DTL usadas arriba:

Etiqueta / FiltroQué hace
{% extends "…" %}Hereda de una plantilla base
{% block name %}Define una sección reemplazable
{{ variable }}Muestra un valor (escapado en HTML automáticamente)
{% for … %} / {% empty %}Bucle con alternativa para listas vacías
|date:"N j, Y"Formatea un valor de fecha y hora
|truncatewords:30Acorta el texto a 30 palabras

Configurar URLs

La configuración de URL mapea las rutas de solicitudes a las funciones de vista.

blog/urls.py — crea este archivo en el directorio blog:

from django.urls import path
from . import views

app_name = 'blog'   # Enables namespaced URL reversing

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('<int:pk>/', views.post_detail, name='post_detail'),
]

mysite/urls.py — incluye las URLs de la app en la raíz del proyecto:

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls', namespace='blog')),
    path('', include('blog.urls', namespace='blog_root')),
]

El convertidor de ruta <int:pk> captura un entero de la URL y lo pasa como argumento de palabra clave pk a post_detail.

Verificar el flujo completo

Inicia el servidor de desarrollo:

python manage.py runserver

Luego abre http://127.0.0.1:8000/ en tu navegador. Si aún no existen publicaciones, la plantilla muestra "No posts yet." Inicia sesión en http://127.0.0.1:8000/admin/ y añade una publicación. Recarga la página de inicio — la publicación aparece inmediatamente.

El ciclo de vida de la solicitud para la página de inicio es:

  1. El navegador envía GET /
  2. El despachador de URL de Django coincide con '' y llama a post_list
  3. post_list consulta Post.objects.all() (se traduce a SELECT * FROM blog_post ORDER BY date_posted DESC)
  4. Django renderiza post_list.html insertando las publicaciones en la plantilla
  5. El HTML renderizado se devuelve al navegador

Referencia rápida del ORM de Django

El ORM te permite construir consultas SQL usando cadenas de métodos Python. Conocer las búsquedas más comunes ahorra mucho tiempo:

# All posts
Post.objects.all()

# Posts by a specific author
Post.objects.filter(author__username='alice')

# Posts containing a word in the title (case-insensitive)
Post.objects.filter(title__icontains='django')

# The five most recent posts
Post.objects.order_by('-date_posted')[:5]

# Count posts
Post.objects.count()

# Get one object (raises DoesNotExist if not found)
Post.objects.get(pk=1)

# Exclude posts by a specific author
Post.objects.exclude(author__username='alice')

Cada una de estas genera una consulta SQL solo cuando el queryset se evalúa (al iterarlo, cortarlo o convertirlo en una lista). Esto se llama evaluación perezosa y mantiene al mínimo las llamadas innecesarias a la base de datos.

Resumen de la estructura del proyecto

Tras completar este tutorial, la estructura del proyecto es la siguiente:

mysite/
├── manage.py
├── mysite/
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── blog/
    ├── admin.py
    ├── migrations/
    │   └── 0001_initial.py
    ├── models.py
    ├── templates/
    │   └── blog/
    │       ├── base.html
    │       ├── post_list.html
    │       └── post_detail.html
    ├── urls.py
    └── views.py

Errores comunes

Olvidar registrar la app. Si 'blog' no está en INSTALLED_APPS, Django no encontrará sus modelos ni plantillas y makemigrations no generará ninguna salida para esa app.

Omitir migrate tras makemigrations. Ejecutar solo makemigrations crea el archivo de migración pero no toca la base de datos. Siempre sigue con migrate.

Errores de plantilla no encontrada. Django busca plantillas dentro del directorio templates/ de cada app. La subcarpeta blog/ adicional dentro de templates/ (templates/blog/post_list.html) es una convención que evita colisiones de nombres entre apps — no la omitas.

DEBUG = True en producción. El servidor de desarrollo y DEBUG = True exponen trazas de error a cualquier persona. Establece DEBUG = False y configura ALLOWED_HOSTS antes de desplegar.

Próximos pasos

La documentación oficial de Django en docs.djangoproject.com cubre las vistas basadas en clases, formularios, autenticación, APIs REST con Django REST Framework y el despliegue en producción — todos ellos pasos naturales una vez que domines los fundamentos cubiertos aquí.

Was this page helpful?