Introducción a Django

Framework web de Python: patrones MVC/MTV, gestión de proyectos, URLs, vistas, plantillas y modelos

Objetivos de Aprendizaje

Introducción a Django

¿Qué es Django?

Django es un framework web de alto nivel escrito en Python que fomenta el desarrollo rápido y el diseño limpio y pragmático. Fue desarrollado para ayudar a los desarrolladores a llevar aplicaciones desde el concepto hasta la finalización lo más rápido posible.

Desarrollo Rápido

Framework que acelera el desarrollo web

Seguro

Protección contra vulnerabilidades comunes

Escalable

Maneja tráfico de alto volumen

Versátil

Desde sitios simples hasta aplicaciones complejas

Filosofía de Django

DRY (Don't Repeat Yourself): Evita la duplicación de código
Convención sobre Configuración: Configuración mínima necesaria
Desarrollo Rápido: De la idea a la producción rápidamente

Patrón de Arquitectura MVC y MTV

Patrón MVC (Model-View-Controller)

Model

Gestiona datos y lógica de negocio

View

Presenta datos al usuario

Controller

Maneja la lógica de control

Patrón MTV (Model-Template-View) en Django

Model

Define la estructura de datos

  • Clases Python que heredan de models.Model
  • Mapeo objeto-relacional (ORM)
  • Validación de datos

Template

Define la presentación

  • Archivos HTML con sintaxis Django
  • Sistema de plantillas con herencia
  • Filtros y etiquetas personalizadas

View

Contiene la lógica de negocio

  • Funciones o clases Python
  • Procesa peticiones HTTP
  • Retorna respuestas HTTP

Flujo de Datos en Django MTV

1

URL Dispatcher

Recibe la petición y la dirige a la vista correspondiente

2

View

Procesa la petición y consulta el modelo si es necesario

3

Model

Interactúa con la base de datos y retorna datos

4

Template

Renderiza los datos en HTML y retorna la respuesta

Instalación y Gestión de Proyectos

Instalación de Django

1. Preparar el Entorno

# Crear entorno virtual
python -m venv django_env

# Activar entorno virtual
# En Windows:
django_env\Scripts\activate
# En Linux/Mac:
source django_env/bin/activate

# Actualizar pip
pip install --upgrade pip

2. Instalar Django

# Instalar Django
pip install Django

# Verificar instalación
python -m django --version

# Instalar dependencias adicionales
pip install pillow          # Para manejo de imágenes
pip install python-decouple # Para variables de entorno
pip install psycopg2-binary # Para PostgreSQL

3. Crear Proyecto Django

# Crear nuevo proyecto
django-admin startproject mi_proyecto

# Estructura del proyecto creado
mi_proyecto/
    manage.py
    mi_proyecto/
        __init__.py
        settings.py
        urls.py
        wsgi.py
        asgi.py

4. Crear Aplicación

# Navegar al directorio del proyecto
cd mi_proyecto

# Crear nueva aplicación
python manage.py startapp mi_app

# Estructura de la aplicación
mi_app/
    __init__.py
    admin.py
    apps.py
    models.py
    tests.py
    views.py
    migrations/

Estructura de Proyecto Django

Archivos Principales

manage.py

Utilidad de línea de comandos para interactuar con el proyecto

settings.py

Configuración del proyecto Django

urls.py

Configuración de URLs del proyecto

wsgi.py

Punto de entrada para servidores web compatibles con WSGI

models.py

Definición de modelos de datos

views.py

Lógica de las vistas

Integración con Apache

Configuración para Producción

La integración con Apache permite servir aplicaciones Django en entornos de producción de manera eficiente y segura.

1. Instalar mod_wsgi

# En Ubuntu/Debian
sudo apt-get install libapache2-mod-wsgi-py3

# En CentOS/RHEL
sudo yum install python3-mod_wsgi

# Habilitar módulo
sudo a2enmod wsgi

2. Configurar Virtual Host

# /etc/apache2/sites-available/mi_proyecto.conf
<VirtualHost *:80>
    ServerName mi-dominio.com
    DocumentRoot /var/www/mi_proyecto
    
    WSGIDaemonProcess mi_proyecto python-path=/var/www/mi_proyecto
    WSGIProcessGroup mi_proyecto
    WSGIScriptAlias / /var/www/mi_proyecto/mi_proyecto/wsgi.py
    
    <Directory /var/www/mi_proyecto/mi_proyecto>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>
    
    Alias /static /var/www/mi_proyecto/static
    <Directory /var/www/mi_proyecto/static>
        Require all granted
    </Directory>
    
    Alias /media /var/www/mi_proyecto/media
    <Directory /var/www/mi_proyecto/media>
        Require all granted
    </Directory>
</VirtualHost>

3. Configurar settings.py para Producción

# settings.py
import os
from decouple import config

# Configuración de producción
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = ['mi-dominio.com', 'www.mi-dominio.com']

# Base de datos
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': config('DB_NAME'),
        'USER': config('DB_USER'),
        'PASSWORD': config('DB_PASSWORD'),
        'HOST': config('DB_HOST', default='localhost'),
        'PORT': config('DB_PORT', default='5432'),
    }
}

# Archivos estáticos
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

# Archivos de media
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Creación de Estructura de Proyectos en Línea de Comandos

Comandos Esenciales de Django

Gestión de Proyectos

# Crear proyecto
django-admin startproject nombre_proyecto

# Crear aplicación
python manage.py startapp nombre_app

# Ejecutar servidor de desarrollo
python manage.py runserver

# Ejecutar en puerto específico
python manage.py runserver 8080

# Ejecutar en IP específica
python manage.py runserver 0.0.0.0:8000

Gestión de Base de Datos

# Crear migraciones
python manage.py makemigrations

# Aplicar migraciones
python manage.py migrate

# Ver migraciones
python manage.py showmigrations

# Migración específica
python manage.py migrate nombre_app 0001

# Crear superusuario
python manage.py createsuperuser

Utilidades

# Shell interactivo de Django
python manage.py shell

# Recopilar archivos estáticos
python manage.py collectstatic

# Verificar proyecto
python manage.py check

# Ejecutar tests
python manage.py test

# Crear fixture de datos
python manage.py dumpdata app.model > fixture.json

# Cargar fixture
python manage.py loaddata fixture.json

Gestión de URLs, Vistas y Plantillas

URLs
Vistas
Plantillas

Sistema de URLs en Django

Django utiliza un sistema de URLs que mapea patrones de URL a vistas específicas.

URLs del Proyecto Principal

# mi_proyecto/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

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

# Servir archivos media en desarrollo
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, 
                         document_root=settings.MEDIA_ROOT)

URLs de la Aplicación

# mi_app/urls.py
from django.urls import path
from . import views

app_name = 'mi_app'

urlpatterns = [
    path('', views.index, name='index'),
    path('detalle/<int:id>/', views.detalle, name='detalle'),
    path('crear/', views.crear, name='crear'),
    path('editar/<int:id>/', views.editar, name='editar'),
    path('eliminar/<int:id>/', views.eliminar, name='eliminar'),
    
    # URLs con parámetros
    path('categoria/<str:nombre>/', views.categoria, name='categoria'),
    path('buscar/', views.buscar, name='buscar'),
    
    # URLs con expresiones regulares
    path('archivo/<slug:slug>/', views.archivo, name='archivo'),
]

Vistas en Django

Las vistas contienen la lógica de negocio y procesan las peticiones HTTP.

Vistas Basadas en Funciones

# views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse, JsonResponse
from django.contrib.auth.decorators import login_required
from .models import MiModelo
from .forms import MiFormulario

def index(request):
    """Vista principal que muestra lista de objetos"""
    objetos = MiModelo.objects.all()
    context = {
        'objetos': objetos,
        'titulo': 'Lista de Objetos'
    }
    return render(request, 'mi_app/index.html', context)

def detalle(request, id):
    """Vista de detalle de un objeto específico"""
    objeto = get_object_or_404(MiModelo, id=id)
    return render(request, 'mi_app/detalle.html', {'objeto': objeto})

@login_required
def crear(request):
    """Vista para crear nuevo objeto"""
    if request.method == 'POST':
        form = MiFormulario(request.POST)
        if form.is_valid():
            form.save()
            return redirect('mi_app:index')
    else:
        form = MiFormulario()
    
    return render(request, 'mi_app/crear.html', {'form': form})

Vistas Basadas en Clases

# views.py
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from .models import MiModelo

class MiListView(ListView):
    model = MiModelo
    template_name = 'mi_app/lista.html'
    context_object_name = 'objetos'
    paginate_by = 10
    
    def get_queryset(self):
        return MiModelo.objects.filter(activo=True)

class MiDetailView(DetailView):
    model = MiModelo
    template_name = 'mi_app/detalle.html'
    context_object_name = 'objeto'

class MiCreateView(LoginRequiredMixin, CreateView):
    model = MiModelo
    fields = ['nombre', 'descripcion', 'categoria']
    template_name = 'mi_app/crear.html'
    success_url = reverse_lazy('mi_app:lista')
    
    def form_valid(self, form):
        form.instance.autor = self.request.user
        return super().form_valid(form)

Sistema de Plantillas Django

Las plantillas definen la presentación y permiten separar la lógica de la presentación.

Plantilla Base

<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Mi Sitio{% endblock %}</title>
    <link rel="stylesheet" href="{% load static %}{% static 'css/style.css' %}">
    {% block extra_css %}{% endblock %}
</head>
<body>
    <header>
        <nav>
            <a href="{% url 'mi_app:index' %}">Inicio</a>
            {% if user.is_authenticated %}
                <a href="{% url 'mi_app:crear' %}">Crear</a>
                <a href="{% url 'logout' %}">Salir</a>
            {% else %}
                <a href="{% url 'login' %}">Iniciar Sesión</a>
            {% endif %}
        </nav>
    </header>
    
    <main>
        {% block content %}{% endblock %}
    </main>
    
    <footer>
        <p>© 2023 Mi Sitio Web</p>
    </footer>
    
    {% block extra_js %}{% endblock %}
</body>
</html>

Plantilla que Hereda

<!-- templates/mi_app/index.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ titulo }} - {{ block.super }}{% endblock %}

{% block content %}
<div class="container">
    <h1>{{ titulo }}</h1>
    
    {% if objetos %}
        <div class="grid">
            {% for objeto in objetos %}
                <div class="card">
                    <h3>
                        <a href="{% url 'mi_app:detalle' objeto.id %}">
                            {{ objeto.nombre }}
                        </a>
                    </h3>
                    <p>{{ objeto.descripcion|truncatewords:20 }}</p>
                    <small>Creado: {{ objeto.fecha_creacion|date:"d/m/Y" }}</small>
                </div>
            {% endfor %}
        </div>
        
        {% if is_paginated %}
            <div class="pagination">
                {% if page_obj.has_previous %}
                    <a href="?page=1">Primera</a>
                    <a href="?page={{ page_obj.previous_page_number }}">Anterior</a>
                {% endif %}
                
                <span>Página {{ page_obj.number }} de {{ page_obj.paginator.num_pages }}</span>
                
                {% if page_obj.has_next %}
                    <a href="?page={{ page_obj.next_page_number }}">Siguiente</a>
                    <a href="?page={{ page_obj.paginator.num_pages }}">Última</a>
                {% endif %}
            </div>
        {% endif %}
    {% else %}
        <p>No hay objetos disponibles.</p>
    {% endif %}
</div>
{% endblock %}

Modelo de Datos y API para Base de Datos

Modelos en Django

Los modelos definen la estructura de los datos y proporcionan una API de alto nivel para interactuar con la base de datos.

Definición de Modelos

# models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse

class Categoria(models.Model):
    nombre = models.CharField(max_length=100, unique=True)
    descripcion = models.TextField(blank=True)
    activa = models.BooleanField(default=True)
    fecha_creacion = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        verbose_name = "Categoría"
        verbose_name_plural = "Categorías"
        ordering = ['nombre']
    
    def __str__(self):
        return self.nombre

class Articulo(models.Model):
    ESTADO_CHOICES = [
        ('borrador', 'Borrador'),
        ('publicado', 'Publicado'),
        ('archivado', 'Archivado'),
    ]
    
    titulo = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    contenido = models.TextField()
    resumen = models.CharField(max_length=300, blank=True)
    autor = models.ForeignKey(User, on_delete=models.CASCADE)
    categoria = models.ForeignKey(Categoria, on_delete=models.SET_NULL, null=True)
    etiquetas = models.ManyToManyField('Etiqueta', blank=True)
    imagen = models.ImageField(upload_to='articulos/', blank=True, null=True)
    estado = models.CharField(max_length=20, choices=ESTADO_CHOICES, default='borrador')
    fecha_creacion = models.DateTimeField(auto_now_add=True)
    fecha_actualizacion = models.DateTimeField(auto_now=True)
    vistas = models.PositiveIntegerField(default=0)
    
    class Meta:
        ordering = ['-fecha_creacion']
        indexes = [
            models.Index(fields=['estado', 'fecha_creacion']),
        ]
    
    def __str__(self):
        return self.titulo
    
    def get_absolute_url(self):
        return reverse('blog:detalle', kwargs={'slug': self.slug})
    
    @property
    def es_reciente(self):
        from django.utils import timezone
        from datetime import timedelta
        return self.fecha_creacion >= timezone.now() - timedelta(days=7)

class Etiqueta(models.Model):
    nombre = models.CharField(max_length=50, unique=True)
    color = models.CharField(max_length=7, default='#007bff')  # Color hexadecimal
    
    def __str__(self):
        return self.nombre

API de Consultas (ORM)

# Ejemplos de uso del ORM de Django

# Crear objetos
categoria = Categoria.objects.create(
    nombre="Tecnología",
    descripcion="Artículos sobre tecnología"
)

articulo = Articulo(
    titulo="Mi primer artículo",
    contenido="Contenido del artículo...",
    autor=request.user,
    categoria=categoria
)
articulo.save()

# Consultas básicas
todos_articulos = Articulo.objects.all()
articulos_publicados = Articulo.objects.filter(estado='publicado')
articulo_especifico = Articulo.objects.get(id=1)

# Consultas avanzadas
articulos_recientes = Articulo.objects.filter(
    fecha_creacion__gte=timezone.now() - timedelta(days=30)
).order_by('-fecha_creacion')

# Consultas con relaciones
articulos_con_categoria = Articulo.objects.select_related('categoria', 'autor')
articulos_con_etiquetas = Articulo.objects.prefetch_related('etiquetas')

# Agregaciones
from django.db.models import Count, Avg
stats = Articulo.objects.aggregate(
    total=Count('id'),
    promedio_vistas=Avg('vistas')
)

# Consultas complejas
articulos_populares = Articulo.objects.filter(
    estado='publicado',
    vistas__gt=100
).exclude(
    categoria__nombre='Privado'
).order_by('-vistas')[:10]

# Búsqueda de texto
from django.db.models import Q
resultados = Articulo.objects.filter(
    Q(titulo__icontains=query) | Q(contenido__icontains=query)
)

Laboratorio 11: Desarrollo de Vistas, Plantillas y Modelos

Objetivos del Laboratorio

  • Crear un proyecto Django completo desde cero
  • Implementar modelos con relaciones complejas
  • Desarrollar vistas basadas en funciones y clases
  • Crear sistema de plantillas con herencia
  • Implementar funcionalidades CRUD completas

Proyecto: Sistema de Blog Avanzado

Desarrollaremos un sistema de blog completo con gestión de usuarios, categorías, comentarios y sistema de etiquetas.

Gestión de Artículos

  • CRUD completo de artículos
  • Sistema de categorías y etiquetas
  • Editor de contenido enriquecido
  • Gestión de imágenes

Sistema de Usuarios

  • Registro y autenticación
  • Perfiles de usuario
  • Roles y permisos
  • Dashboard de autor

Interacción Social

  • Sistema de comentarios
  • Valoraciones de artículos
  • Compartir en redes sociales
  • Suscripción a newsletter

Funcionalidades Avanzadas

  • Búsqueda avanzada
  • Paginación inteligente
  • SEO optimizado
  • Panel de administración

Resumen Semana 11

Arquitectura Django

Comprensión profunda del patrón MTV y su implementación en Django para desarrollo web estructurado.

Configuración de Proyectos

Dominio de la instalación, configuración y gestión de proyectos Django desde desarrollo hasta producción.

URLs y Vistas

Implementación efectiva del sistema de URLs y desarrollo de vistas tanto funcionales como basadas en clases.

Sistema de Plantillas

Creación de interfaces dinámicas usando el sistema de plantillas con herencia, bloques y filtros.

Modelos y ORM

Diseño de modelos de datos complejos y uso eficiente del ORM para interacciones con base de datos.

Integración Apache

Configuración profesional para despliegue en producción con Apache y mod_wsgi.