Análisis detallado del código fuente de APIView en Django REST Framework

Exploración del código fuente de APIView

1. Análisis del código de vistas basadas en clases

1.1 Importación y uso de View

# Importación de la clase base View de Django
from django.views import View

class ColeccionLibros(View):
    def obtener(self, peticion):
        return HttpResponse('respuesta_ok')

# Configuración en urls.py
path('libros_fbv/', vistas.funcion_libros),
path('libros_cbv/', vistas.ColeccionLibros.as_view())

1.2 Método as_view() de View

El método as_view() funciona como un closure que devuelve una función interna:

@classonlymethod
def as_view(clase, **parametros_iniciales):
    def vista_interna(peticion, *args, **kwargs):
        # Se obtiene la clase que invoca el método
        instancia = clase(**parametros_iniciales)
        # Se_delega al método dispatch de la instancia
        return instancia.dispatch(peticion, *args, **kwargs)

    vista_interna.clase_vista = clase
    vista_intea.parametros_iniciales = parametros_iniciales
    return vista_interna

1.3 Método dispatch() de View

metodos_http = ["get", "post", "put", "patch", "delete", "head", "options", "trace"]

def dispatch(self, peticion, *args, **kwargs):
    # Verificación del método HTTP solicitado
    nombre_metodo = peticion.method.lower()
    if nombre_metodo in self.metodos_http:
        #反射 para obtener el método corresponding
        manejador = getattr(
            self, nombre_metodo, self.metodo_no_permitido
        )
    else:
        manejador = self.metodo_no_permitido
    
    # Ejecución del manejador encontrado
    return manejador(peticion, *args, **kwargs)

2. Análisis del código de APIView

2.1 Importación de APIView

from rest_framework.views import APIView

class LibrosAPIView(APIView):
    def crear(self, peticion):
        print(peticion.datos)
        
        archivo = peticion.FILES.get('archivo')
        with open('imagen.png', 'wb') as f:
            for bloque in archivo:
                f.write(bloque)
        
        return HttpResponse('procesado')

# urls.py
path('api_libros/', vistas.LibrosAPIView.as_view())

2.2 Método as_view() de APIView

from django.views.generic.base import View
from django.views.decorators.csrf import csrf_exempt

class APIView(View):
    @classmethod
    def as_view(clase, **parametros_iniciales):
        #llamada al método de la clase padre
        vista = super().as_view(**parametros_iniciales)
        
        # Decorador para desactivar CSRF en todas las vista API View
        vista.clase_origen = clase
        vista.configuracion = parametros_iniciales
        
        return csrf_exempt(vista)

2.3 Método dispatch() de la clase padre (View)

@classonlymethod
def as_view(clase, **parametros_iniciales):
    def wrapper(peticion, *args, **kwargs):
        instancia = clase(**parametros_iniciales)
        # dispatch utilizará el método de APIView
        return instancia.dispatch(peticion, *args, **kwargs)

    wrapper.clase_vista = clase
    wrapper.parametros_iniciales = parametros_iniciales
    return wrapper

2.4 Método dispatch() de APIView

def dispatch(self, peticion, *args, **kwargs):
    self.args = args
    self.kwargs = kwargs
    
    # Envoltura del objeto request original
    peticion_procesada = self.inicializar_peticion(peticion, *args, **kwargs)
    self.peticion = peticion_procesada
    self.cabeceras = self.obtener_cabeceras_respuesta()

    try:
        # Validación de autenticación, permisos y limitación de frecuencia
        self.inicial(procesada, *args, **kwargs)
        
        # Selección del manejador según el método HTTP
        metodo_http = peticion_procesada.method.lower()
        if metodo_http in self.nombres_metodos_http:
            manejador = getattr(
                self, metodo_http, self.metodo_no_permitido
            )
        else:
            manejador = self.metodo_no_permitido

        respuesta = manejador(peticion_procesada, *args, **kwargs)

    except Exception as error:
        respuesta = self.manejar_excepcion(error)

    self.respuesta = self.finalizar_respuesta(
        peticion_procesada, respuesta, *args, **kwargs
    )
    return self.respuesta

2.4.1 Método initialize_request() de APIView
def inicializar_peticion(self, peticion, *args, **kwargs):
    contexto = self.obtener_contexto_parsers(peticion)
    return Request(
        peticion,
        parsers=self.obtener_parsers(),
        autenticadores=self.obtener_autenticadores(),
        negociador=self.obtener_negociador_contenido(),
        contexto=contexto
    )

La clase Request envolvió el objeto HttpRequest original:

from rest_framework.request import Request

# Request redefine __getattr__ para mantener compatibilidad
def __getattr__(self, atributo):
    try:
        return getattr(self.peticion_origen, atributo)
    except AttributeError:
        return self.__getattribute__(atributo)

Propiedades importantes del nuevo Request:

  • request.data: Contiene los datos del cuerpo de la petición (POST, JSON, form-data)
  • request.query_params: Alias semánticamente correcto para request.GET
2.4.2 Método initial() de APIView
def inicial(self, peticion, *args, **kwargs):
    # Control de versión de la API
    version_esquema = self.determinar_version(peticion, *args, **kwargs)
    peticion.version, peticion.esquema_version = version_esquema

    # Componente de autenticación: verifica identidad del usuario
    self.ejecutar_autenticacion(peticion)
    
    # Componente de permisos: verifica derechos de acceso
    self.verificar_permisos(peticion)
    
    # Componente de throttling: limita frecuencia de acceso
    self.verificar_limitacion(peticion)

3. Resumen del flujo de ejecución

El flujo completo de una petición en APIView sigue esta secuencia:

  1. UrlRouter invoca la función retornada por as_view()
  2. Se crea una instancia de la clase vista
  3. Se llama al método dispatch() de APIView
  4. Se envuelve el request original en un objeto Request
  5. Se ejecuta el método initial() que incluye autenticación, permisos y throttling
  6. Se selecciona el manejador correspondiente al método HTTP
  7. Se procesa la excepción si ocurre algún error
  8. Se retorna la respuesta final

Publicado el 7-22 12:55