[ DOC.SPEC ]DjangoPythonDesarrollo WebBuenas Prácticas

Vistas Basadas en Clases (CBV) vs. Vistas Basadas en Funciones (FBV): Una Comparativa Detallada

//TIEMPO: 5 min

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_decorator o 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) o method_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/elif gigantes: 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.

← [ REGRESAR AL ÍNDICE DE ARTÍCULOS ]