Vistas Basadas en Clases (CBV) vs. Vistas Basadas en Funciones (FBV): Una Comparativa Detallada
Vistas Basadas en Clases (CBV) vs. Vistas Basadas en Funciones (FBV): Una Comparativa Detallada
Resumen ejecutivo
- FBV: ideales para endpoints simples y explícitos. Menor “magia”, curva de aprendizaje suave, fáciles de leer y depurar.
- CBV: destacan en reutilización y extensibilidad (mixins, herencia, genéricos). Reducen repetición cuando el proyecto crece y los patrones se repiten.
Fundamentos
FBV (Function-Based Views)
Una FBV es una función que recibe request y devuelve HttpResponse (o lanza excepciones).
# views.py
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
@login_required
def hello(request):
if request.method == "GET":
return HttpResponse("Hola mundo")
return HttpResponse(status=405) # Método no permitido
Ventajas
- Explícitas: el flujo se ve de arriba a abajo.
- Sencillas para casos pequeños o endpoints ad-hoc.
- Decoradores muy directos (
@login_required,@permission_required, etc.). - Testing directo: llamas a la función o usas el test client.
Desventajas
- Pueden duplicar lógica cuando crece el proyecto (validaciones, permisos, patrones CRUD).
- Manejar múltiples métodos HTTP puede derivar en condicionales grandes.
CBV (Class-Based Views)
Una CBV es una clase con métodos por verbo (get, post, …) y un dispatch que enruta según el método.
# views.py
from django.views import View
from django.http import HttpResponse
from django.contrib.auth.mixins import LoginRequiredMixin
class HelloView(LoginRequiredMixin, View):
def get(self, request):
return HttpResponse("Hola mundo")
Ventajas
- Organización por métodos (limpia para GET/POST/PUT/DELETE).
- Herencia y mixins → fuerte DRY y reutilización.
- Genéricas (ListView, DetailView, CreateView, …) aceleran CRUD.
- Extensibles: sobreescribes hooks (
get_queryset,form_valid,get_context_data, …).
Desventajas
- Curva de aprendizaje mayor (MRO, mixins, hooks).
- “Magia”/indirección: el flujo no siempre es obvio a primera vista.
- Decoradores menos directos (hay que usar
method_decoratoro mixins).
Ejemplos comparados
1) Endpoint simple → FBV gana en legibilidad
FBV
from django.http import JsonResponse
def healthcheck(request):
return JsonResponse({"status": "ok"})
CBV (correcta, pero más verbosa para algo trivial)
from django.views import View
from django.http import JsonResponse
class HealthcheckView(View):
def get(self, request):
return JsonResponse({"status": "ok"})
Para un ping/healthcheck o respuestas muy simples, FBV suele ser más clara.
2) CRUD repetido → CBV genéricas reducen código
FBV (esquema conceptual: acabarás repitiendo patrones)
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post
from .forms import PostForm
def post_list(request):
posts = Post.objects.all()
return render(request, "post_list.html", {"posts": posts})
def post_create(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect("post_list")
else:
form = PostForm()
return render(request, "post_form.html", {"form": form})
# ... y así para detail, update, delete (mucho código repetido)
CBV genéricas (Django trae lo “difícil” hecho)
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Post
class PostListView(LoginRequiredMixin, ListView):
model = Post
paginate_by = 20
class PostDetailView(LoginRequiredMixin, DetailView):
model = Post
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ["title", "body"]
success_url = reverse_lazy("post_list")
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ["title", "body"]
success_url = reverse_lazy("post_list")
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
success_url = reverse_lazy("post_list")
Para CRUD estándar, las CBV genéricas son difícilmente superables en productividad y DRY.
Mixins y herencia: el punto fuerte de las CBV
Mixins para permisos/filtrado reutilizable
from django.core.exceptions import PermissionDenied
class OwnerRequiredMixin:
"""
Restringe acceso a objetos que no pertenecen al usuario.
Reutilizable en varias vistas CBV (Detail/Update/Delete).
"""
owner_field = "owner"
def get_object(self, queryset=None):
obj = super().get_object(queryset)
if getattr(obj, self.owner_field) != self.request.user:
raise PermissionDenied()
return obj
Aplicación en varias vistas:
class MyPostDetailView(LoginRequiredMixin, OwnerRequiredMixin, DetailView):
model = Post
class MyPostUpdateView(LoginRequiredMixin, OwnerRequiredMixin, UpdateView):
model = Post
fields = ["title", "body"]
Hooks para añadir contexto y lógica transversal
class ContextMixin:
extra_title = None
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
if self.extra_title:
ctx["title"] = self.extra_title
return ctx
class PostListView(ContextMixin, ListView):
model = Post
extra_title = "Mis Posts"
Con mixins y hooks, encapsulas políticas transversales (propiedad, auditoría, contextos, rate limiting, etc.) y las reutilizas sin copiar/pegar.
Decoradores y CBV: patrones
- FBV: directo con
@login_required. - CBV: usa mixins (
LoginRequiredMixin) omethod_decorator:
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.views import View
@method_decorator(login_required, name="dispatch")
class SecureView(View):
def get(self, request):
...
Regla práctica: prefiere mixins nativos (
LoginRequiredMixin,PermissionRequiredMixin) cuando existan.
Testing
- FBV: test directo y explícito; ideal para endpoints sencillos.
- CBV: testea a través de URL (recomendado) o invocando la vista vía
as_view():
from django.test import RequestFactory, TestCase
from .views import PostListView
class PostListViewTests(TestCase):
def test_ok(self):
rf = RequestFactory()
req = rf.get("/posts/")
resp = PostListView.as_view()(req)
self.assertEqual(resp.status_code, 200)
Para CBV complejas, testear por URL + asserts sobre contexto/plantilla suele ser más mantenible.
Rendimiento y el GIL (visión práctica)
- Diferencias micro entre CBV y FBV son negligibles frente al coste de E/S, DB y plantillas.
- La elección debe priorizar diseño y mantenibilidad.
- Si el rendimiento es crítico, enfócate en consultas, caché, select_related/prefetch_related, paginación y CDN.
Cuándo elegir cada una (checklist)
Usa FBV cuando…
- El endpoint es muy simple (healthcheck, webhook mínimo, 1–2 ramas).
- Necesitas máxima claridad en un hotfix o PoC.
- Quieres control total en pocas líneas sin herencia/mixins.
Usa CBV cuando…
- Hay patrones repetidos (CRUD, permisos, validaciones).
- Requieres múltiples métodos HTTP con flujo claro por método.
- Deseas componer funcionalidades con mixins y hooks.
- Trabajas con genéricas de Django para acelerar desarrollo.
Anti-patrones y consejos
- CBV demasiado profundas: demasiados mixins/herencia → difícil de seguir. Mantén el MRO simple y documenta.
- FBV con
if/elifgigantes: si crece, refactoriza a CBV. - Decoradores en CBV: evita mezclarlos con mixins que ya resuelven lo mismo.
- Nombres de hooks: usa los hooks estándar (
get_queryset,get_form_kwargs,form_valid, etc.) para mantener consistencia con Django.
Conclusión
- FBV: simplicidad y explicitud para endpoints pequeños o muy específicos.
- CBV: reutilización, extensibilidad y DRY para módulos con patrones repetidos y complejidad creciente.
- En equipos y proyectos medianos/grandes, CBV + mixins reducen deuda técnica a largo plazo. En tareas puntuales, FBV mantiene el coste cognitivo al mínimo.
En la práctica: empieza simple con FBV; cuando detectes repetición o complejidad transversal (permisos, ownership, validaciones, CRUD), refactoriza a CBV con mixins.
// TELEMETRÍA // LECTURAS TÉCNICAS RECOMENDADAS
Los Secretos de itertools: Escribiendo Código Eficiente e Idiomático 💡
Descubre cómo el módulo itertools de Python puede ayudarte a escribir código más eficiente, conciso e idiomático para el procesamiento de secuencias.
Optimización con Algoritmos: Cómo un Simple Cambio Aceleró mi Código 100 Veces
Aprende a optimizar tu código con algoritmos de alto nivel, como la calculación de números de Fibonacci. Descubre cómo la elección del algoritmo adecuado puede marcar la diferencia entre una aplicación responsive y una completamente inusable.