Las vistas son funciones o clases que procesan las peticiones HTTP y devuelven respuestas. Las plantillas son archivos HTML que definen cómo se presenta la información al usuario.
Una vista en Django es una función de Python que toma una petición web y devuelve una respuesta web. Esta respuesta puede ser el contenido HTML de una página web, una redirección, un error 404, un documento XML, una imagen, o cualquier otra cosa.
Las vistas contienen la lógica necesaria para procesar una petición y devolver una respuesta.
Las vistas basadas en función son la forma más simple y directa de crear vistas en Django.
# views.py
from django.shortcuts import render
from django.http import HttpResponse
def mi_vista(request):
"""
Vista básica que devuelve una respuesta simple
"""
return HttpResponse("¡Hola, mundo!")
def vista_con_plantilla(request):
"""
Vista que renderiza una plantilla
"""
contexto = {
'titulo': 'Mi Página',
'mensaje': 'Bienvenido a Django'
}
return render(request, 'mi_plantilla.html', contexto)
request
como primer parámetro. Este objeto contiene información sobre la petición HTTP.
# views.py
from django.shortcuts import render
from .models import Producto
def lista_productos(request):
"""
Vista que muestra todos los productos
"""
productos = Producto.objects.all()
contexto = {
'productos': productos,
'titulo': 'Lista de Productos'
}
return render(request, 'productos/lista.html', contexto)
def detalle_producto(request, producto_id):
"""
Vista que muestra el detalle de un producto específico
"""
try:
producto = Producto.objects.get(id=producto_id)
except Producto.DoesNotExist:
return HttpResponse("Producto no encontrado", status=404)
contexto = {
'producto': producto
}
return render(request, 'productos/detalle.html', contexto)
Las vistas basadas en clase (CBV) proporcionan una forma más reutilizable y organizada de crear vistas complejas.
# views.py
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Producto
class ProductoListView(ListView):
"""
Vista de lista usando CBV
"""
model = Producto
template_name = 'productos/lista.html'
context_object_name = 'productos'
paginate_by = 10
class ProductoDetailView(DetailView):
"""
Vista de detalle usando CBV
"""
model = Producto
template_name = 'productos/detalle.html'
context_object_name = 'producto'
class ProductoCreateView(CreateView):
"""
Vista para crear productos
"""
model = Producto
template_name = 'productos/crear.html'
fields = ['nombre', 'descripcion', 'precio']
success_url = reverse_lazy('productos:lista')
class ProductoUpdateView(UpdateView):
"""
Vista para actualizar productos
"""
model = Producto
template_name = 'productos/editar.html'
fields = ['nombre', 'descripcion', 'precio']
success_url = reverse_lazy('productos:lista')
Las plantillas son archivos que definen la estructura y el diseño de tus páginas web. Django tiene su propio sistema de plantillas potente y flexible.
<!-- templates/productos/lista.html -->
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>{{ titulo }}</title>
</head>
<body>
<h1>{{ titulo }}</h1>
{% if productos %}
<div class="productos-grid">
{% for producto in productos %}
<div class="producto-card">
<h3>{{ producto.nombre }}</h3>
<p>{{ producto.descripcion|truncatewords:20 }}</p>
<p class="precio">${{ producto.precio }}</p>
<a href="{% url 'productos:detalle' producto.id %}">Ver detalle</a>
</div>
{% endfor %}
</div>
{% else %}
<p>No hay productos disponibles.</p>
{% endif %}
</body>
</html>
{{ variable }}
Muestran el valor de una variable del contexto.
Ejemplo:{{ usuario.nombre }}
{% tag %}
Proporcionan lógica en las plantillas.
Ejemplo:{% if %}, {% for %}, {% url %}
{{ variable|filtro }}
Modifican el valor de las variables.
Ejemplo:{{ fecha|date:"d/m/Y" }}
El contexto es un diccionario que contiene los datos que se pasan desde la vista a la plantilla.
def mi_vista(request):
contexto = {
'titulo': 'Mi Página',
'usuario': request.user,
'productos': Producto.objects.all(),
'fecha_actual': timezone.now(),
'configuracion': {
'mostrar_precios': True,
'moneda': 'EUR'
}
}
return render(request, 'mi_plantilla.html', contexto)
<h1>{{ titulo }}</h1>
<p>Bienvenido, {{ usuario.first_name }}</p>
<p>Fecha: {{ fecha_actual|date:"d/m/Y" }}</p>
{% if configuracion.mostrar_precios %}
{% for producto in productos %}
<div>
<h3>{{ producto.nombre }}</h3>
<p>{{ producto.precio }} {{ configuracion.moneda }}</p>
</div>
{% endfor %}
{% endif %}
Filtro | Descripción | Ejemplo |
---|---|---|
date |
Formatea fechas | {{ fecha|date:"d/m/Y" }} |
truncatewords |
Trunca texto por palabras | {{ texto|truncatewords:10 }} |
length |
Longitud de cadena o lista | {{ lista|length }} |
default |
Valor por defecto | {{ valor|default:"Sin valor" }} |
safe |
Marca HTML como seguro | {{ html_content|safe }} |
La herencia de plantillas permite crear una plantilla base y extenderla en otras plantillas, evitando la duplicación de código.
<!-- 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 Web{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
{% block extra_css %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="/">Mi Sitio</a>
<div class="navbar-nav">
<a class="nav-link" href="{% url 'productos:lista' %}">Productos</a>
<a class="nav-link" href="{% url 'contacto' %}">Contacto</a>
</div>
</div>
</nav>
<main class="container mt-4">
{% block content %}
<!-- Contenido específico de cada página -->
{% endblock %}
</main>
<footer class="bg-dark text-white text-center py-3 mt-5">
<p>© 2024 Mi Sitio Web. Todos los derechos reservados.</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
{% block extra_js %}{% endblock %}
</body>
</html>
<!-- templates/productos/lista.html -->
{% extends 'base.html' %}
{% block title %}Lista de Productos - {{ block.super }}{% endblock %}
{% block extra_css %}
<style>
.producto-card {
border: 1px solid #ddd;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0.5rem;
}
</style>
{% endblock %}
{% block content %}
<h1>{{ titulo }}</h1>
{% if productos %}
<div class="row">
{% for producto in productos %}
<div class="col-md-4 mb-3">
<div class="producto-card">
<h5>{{ producto.nombre }}</h5>
<p>{{ producto.descripcion|truncatewords:15 }}</p>
<p class="text-success fw-bold">${{ producto.precio }}</p>
<a href="{% url 'productos:detalle' producto.id %}" class="btn btn-primary">Ver detalle</a>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="alert alert-info">
<p>No hay productos disponibles en este momento.</p>
</div>
{% endif %}
{% endblock %}
{% block extra_js %}
<script>
// JavaScript específico para la lista de productos
console.log('Lista de productos cargada');
</script>
{% endblock %}
Los patrones de URL conectan las URLs con las vistas correspondientes.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('productos.urls')),
path('productos/', include('productos.urls')),
]
from django.urls import path
from . import views
app_name = 'productos'
urlpatterns = [
path('', views.lista_productos, name='lista'),
path('<int:producto_id>/', views.detalle_producto, name='detalle'),
path('crear/', views.ProductoCreateView.as_view(), name='crear'),
path('<int:pk>/editar/', views.ProductoUpdateView.as_view(), name='editar'),
path('<int:pk>/eliminar/', views.ProductoDeleteView.as_view(), name='eliminar'),
]
Patrón | Descripción | Ejemplo |
---|---|---|
<int:id> |
Captura un entero | productos/123/ |
<str:slug> |
Captura una cadena | productos/mi-producto/ |
<slug:slug> |
Slug válido | productos/mi-producto-123/ |
<uuid:id> |
UUID válido | productos/550e8400-e29b-41d4-a716-446655440000/ |
<!-- Enlace simple -->
<a href="{% url 'productos:lista' %}">Ver productos</a>
<!-- Enlace con parámetros -->
<a href="{% url 'productos:detalle' producto.id %}">Ver detalle</a>
<!-- Enlace con múltiples parámetros -->
<a href="{% url 'productos:editar' categoria=producto.categoria.slug id=producto.id %}">Editar</a>
<!-- Formulario con acción dinámica -->
<form method="post" action="{% url 'productos:crear' %}">
{% csrf_token %}
<!-- campos del formulario -->
</form>
# models.py
class Libro(models.Model):
titulo = models.CharField(max_length=200)
autor = models.CharField(max_length=100)
isbn = models.CharField(max_length=13, unique=True)
fecha_publicacion = models.DateField()
disponible = models.BooleanField(default=True)
descripcion = models.TextField()
def __str__(self):
return self.titulo
# biblioteca/views.py
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.urls import reverse_lazy
from django.db.models import Q
from .models import Libro
class LibroListView(ListView):
model = Libro
template_name = 'biblioteca/lista.html'
context_object_name = 'libros'
paginate_by = 12
def buscar_libros(request):
query = request.GET.get('q')
libros = []
if query:
libros = Libro.objects.filter(
Q(titulo__icontains=query) |
Q(autor__icontains=query)
)
contexto = {
'libros': libros,
'query': query
}
return render(request, 'biblioteca/buscar.html', contexto)
class LibroDetailView(DetailView):
model = Libro
template_name = 'biblioteca/detalle.html'
context_object_name = 'libro'
class LibroCreateView(CreateView):
model = Libro
template_name = 'biblioteca/crear.html'
fields = ['titulo', 'autor', 'isbn', 'fecha_publicacion', 'descripcion']
success_url = reverse_lazy('biblioteca:lista')
# biblioteca/urls.py
from django.urls import path
from . import views
app_name = 'biblioteca'
urlpatterns = [
path('', views.LibroListView.as_view(), name='lista'),
path('libro/<int:pk>/', views.LibroDetailView.as_view(), name='detalle'),
path('crear/', views.LibroCreateView.as_view(), name='crear'),
path('buscar/', views.buscar_libros, name='buscar'),
]
<!-- templates/biblioteca/base.html -->
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>{% block title %}Biblioteca{% endblock %}</title>
<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">
<div class="container">
<a class="navbar-brand" href="{% url 'biblioteca:lista' %}">📚 Biblioteca</a>
<div class="navbar-nav">
<a class="nav-link" href="{% url 'biblioteca:lista' %}">Libros</a>
<a class="nav-link" href="{% url 'biblioteca:crear' %}">Agregar</a>
<a class="nav-link" href="{% url 'biblioteca:buscar' %}">Buscar</a>
</div>
</div>
</nav>
<main class="container mt-4">
{% block content %}{% endblock %}
</main>
</body>
</html>
¿Cuál es la diferencia principal entre una vista basada en función y una vista basada en clase?
¿Qué tag de plantilla se usa para incluir el contenido de un bloque padre?
¿Cuál es la sintaxis correcta para crear un enlace con parámetros en una plantilla?
¿Qué método de vista basada en clase se ejecuta automáticamente para peticiones GET?
¿Cuál es la función del contexto en Django?
Ya puedes continuar con el siguiente módulo
Continuar al Módulo 4