Módulo 5 · Lección 12 de 30
Instalación y primer punto de acceso
Una API funcionando en veinte líneas, y las tres cosas que trae apagadas de fábrica: una de ellas deja que cualquiera borre tus datos.
Django REST Framework se instala y funciona rápido. Tan rápido que se puede tener una API completa antes de haber entendido nada de lo que hace, y eso es exactamente el problema de esta lección.
Vamos a montarla, y después vamos a mirar los ajustes por defecto, que son la parte que no sale en los tutoriales y la que decide si la API es publicable.
La instalación#
pip install djangorestframeworkName: djangorestframework
Version: 3.18.1
Requires: djangoUna sola dependencia, y es Django. Es de las bibliotecas grandes más limpias que hay, y conviene saberlo porque casi todos los tutoriales instalan a la vez cuatro paquetes de terceros que no hacen falta para empezar.
Se registra como una aplicación:
INSTALLED_APPS = [
# ...
'rest_framework',
'catalogo',
]El punto de acceso#
Tres piezas. Primero el serializador, que convierte entre modelos y JSON y es la lección siguiente:
from rest_framework import serializers
from .models import Libro
class LibroSerializer(serializers.ModelSerializer):
class Meta:
model = Libro
fields = '__all__'Después la vista:
from rest_framework import viewsets
class LibroViewSet(viewsets.ModelViewSet):
queryset = Libro.objects.all()
serializer_class = LibroSerializerY las rutas:
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('libros', LibroViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]Con eso hay una API con lista, creación, consulta, modificación y borrado. Y la raíz del enrutador la enseña:
GET /api/
{
"editoriales": "http://127.0.0.1:8077/api/editoriales/",
"autores": "http://127.0.0.1:8077/api/autores/",
"libros": "http://127.0.0.1:8077/api/libros/"
}Un libro concreto:
GET /api/libros/1/
{
"id": 1,
"titulo": "El libro número 0",
"isbn": "978-84-0000-00-0",
"precio": "19.98",
"paginas": 234,
"estado": "publicado",
"publicado_en": "2020-01-01",
"creado": "2026-09-22T21:15:20.844072+02:00",
"editorial": 1,
"autores": [5]
}Tres cosas que mirar antes de seguir:
El precio va entre comillas. Es la decisión de la lección anterior, y DRF la toma por ti con el ajuste COERCE_DECIMAL_TO_STRING, que vale True de fábrica. Acertado: si fuera número, el cliente lo leería como coma flotante.
Las fechas son ISO 8601 con zona horaria, que es lo que la lección 3 pedía.
Las relaciones son identificadores. editorial: 1 y autores: [5]. Es lo que hay que cambiar en la lección 14.
Los errores, en español#
Esto es una alegría para un proyecto en español y casi nadie lo menciona. Con LANGUAGE_CODE = 'es':
DELETE /api/libros/ -> 405 {"detail": "Método \"DELETE\" no permitido."}
POST /api/libros/ {} -> 400 {"titulo": ["Este campo es requerido."],
"isbn": ["Este campo es requerido."], ...}Traducidos solos, sin configurar nada más. DRF viene con las traducciones dentro.
Y la forma de los errores es la de la lección 2, ahora desde el lado que los escribe: un objeto con detail cuando el problema es general, y un objeto con una lista de mensajes por campo cuando son de validación. Esa forma es razonable y merece la pena conocerla, porque es lo que van a recibir tus clientes.
El navegador de la API#
Si abres /api/libros/ en un navegador no sale JSON: sale una página con formularios para probar la API. Es la característica más llamativa de DRF.
Y funciona por negociación de contenido, que es la lección 2 desde el otro lado:
Accept: */* -> application/json 54 044 bytes
Accept: text/html -> text/html; charset=utf-8 132 253 bytesUn navegador manda text/html, así que ve la página; curl manda */* y recibe JSON. Por eso funciona sin que hayas configurado nada.
Es genuinamente útil para explorar y para enseñársela a alguien. Y tiene un coste que hay que conocer:
json 0,042 s 54 044 bytes
html 0,050 s 132 253 bytesDos veces y media más grande, porque construye formularios HTML con todas las opciones de todos los campos de todos los objetos. Con relaciones grandes, eso son desplegables de miles de elementos y la página tarda segundos.
En producción se apaga, dejando solo el renderizador de JSON:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
}Y si quieres conservarlo en desarrollo, es la configuración por entornos de la lección 40 del módulo 4:
# ajustes/desarrollo.py
REST_FRAMEWORK['DEFAULT_RENDERER_CLASSES'] += [
'rest_framework.renderers.BrowsableAPIRenderer',
]Los ajustes de fábrica#
Aquí está lo importante de la lección. Estos son los valores por defecto de DRF, medidos:
DEFAULT_RENDERER_CLASSES [JSONRenderer, BrowsableAPIRenderer]
DEFAULT_PARSER_CLASSES [JSONParser, FormParser, MultiPartParser]
DEFAULT_AUTHENTICATION_CLASSES [SessionAuthentication, BasicAuthentication]
DEFAULT_PERMISSION_CLASSES [AllowAny]
DEFAULT_THROTTLE_CLASSES []
DEFAULT_PAGINATION_CLASS None
PAGE_SIZE None
DEFAULT_FILTER_BACKENDS []
COERCE_DECIMAL_TO_STRING True
DATETIME_FORMAT iso-8601Cuatro de esas líneas son las que hay que cambiar.
No hay paginación. DEFAULT_PAGINATION_CLASS es None, así que un listado devuelve todo:
GET /api/libros/ -> 200 elementos, 54 044 bytes, lista peladaCon doscientos libros son cincuenta kilobytes. Con doscientos mil, la petición tumba el servidor. Y el problema añadido, que es el de la lección anterior: activar la paginación cambia la forma de la respuesta de una lista pelada a un objeto con envoltorio, así que hacerlo más tarde rompe a todos los clientes.
Se activa el primer día:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 50,
}Es la lección 20, y esas dos líneas van desde el principio.
No hay límite de uso. DEFAULT_THROTTLE_CLASSES está vacío: cualquiera puede pedir mil veces por segundo. Es todo el bloque A visto desde el otro lado, y se configura con AnonRateThrottle y UserRateThrottle.