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:
- UrlRouter invoca la función retornada por as_view()
- Se crea una instancia de la clase vista
- Se llama al método dispatch() de APIView
- Se envuelve el request original en un objeto Request
- Se ejecuta el método initial() que incluye autenticación, permisos y throttling
- Se selecciona el manejador correspondiente al método HTTP
- Se procesa la excepción si ocurre algún error
- Se retorna la respuesta final