API Django para procesamiento de imágenes
Al momento de trabajar con imágenes, o datos en general, existen ocasiones en las que la máquina en la cual trabajamos es distinta de aquella en donde realizamos el procesamiento(un servidor on-premise o cloud, por ejemplo). Si no deseamos trabajar directamente en el servidor, con todo lo que ello implica, podemos optar por configurar este último como una API para el procesamiento. En este articulo lo haremos utilizando el framework Django en lenguaje Python.
Django
Django es un framework de Python para el desarrollo web. Adicionalmente, haremos uso del Django REST Framework (DRF), el cual en un toolkit para el desarrollo de APIs. Algunos conceptos importantes a conocer son serializers, vistas y urls:
- Serializer: Es una herramienta de DRF que facilita el intercambio de datos entre cliente y servidor al asegurar que la entrada y la salida de datos estén en el formato correcto y sean adecuadas para su consumo en diferentes contextos.
- Vistas: Funcionan como el puente entre los modelos de datos y los templates, manejando la lógica necesaria para procesar las peticiones de los usuarios y devolver las respuestas correctas.
- URLS: Actúan como el mapeador entre las peticiones HTTP que recibe un sitio web y el código Python que las maneja. Este mapeo se define en lo que Django llama el “sistema de enrutamiento de URL”, que utiliza expresiones regulares o rutas de estilo de ruta para capturar patrones de URL y dirigirlos a las vistas adecuadas.
Con estos conceptos claros, podemos comenzar el desarrollo.
Paso 1: Instalar Django, crear proyecto y aplicacion
Primero instalamos Django y DRF con:
pip install django djangorestframework Pillow
Luego creamos nuesto proyecto (ImageAPI) ejecutando:
django-admin startproject ImageAPI
A continuación, en la carpeta de nuestro proyecto, creamos nuestra aplicación (imageapp) con:
python manage.py startapp imageapp
Luego creamos/modificamos el archivo ImageAPI/settings.py
para agregar los elementos rest_framework e imageapp a la lista INSTALLED_APPS. Aquí cabe destacar que un proyecto puede tener multiples aplicaciones.
INSTALLED_APPS = ['rest_framework',
'imageapp',]
Paso 2: Definir serializer, vista y url
Comenzamos por el serializer, el cual se encargará de estandarizar la comunicación entre cliente y servidor. Para esto editamos nuestro archivo imageapp/serializers.py
y agregamos:
from rest_framework import serializers
class ImageUploadSerializer(serializers.Serializer):
image = serializers.ImageField()
Notamos que nuestro ImageUploadSerializer
utiliza serializers.ImageField()
, lo que nos permite verificar que el archivo cargado sea un tipo de archivo de imagen válido, también asegura que se respeten los límites de tamaño de archivo (si están configurados) y valida que el archivo no esté corrupto y pueda ser procesado correctamente.
A continuación definimos nuestra vista, la cual usara nuestro serializer para cargar una imagen, procesarla y luego devolver un resultado. Para definirla editamos el archivo imageapp/views.py
agregando:
from rest_framework.views import APIView
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from .serializers import ImageUploadSerializer
def process_image(image_file):
# Lógica para procesar la imagen
# Por ejemplo, calcular el tamaño de la imagen
return {'details': f'Processed image size: {image_file.size} bytes'}
class ImageProcessView(APIView):
parser_classes = [MultiPartParser, FormParser]
def post(self, request, *args, **kwargs):
serializer = ImageUploadSerializer(data=request.data)
if serializer.is_valid():
image_file = serializer.validated_data['image']
result = process_image(image_file)
return Response(result)
return Response(serializer.errors, status=400)
Como podemos ver, la vista ImageProcessView
hereda de APIView
, que es una clase nativa de DRF diseñada para manejar vistas relacionadas con APIs. Utilizar APIView
nos ayuda a tener un manejo claro y estructurado de diferentes métodos HTTP. En nuestro caso, estamos implementando el método post
para manejar las cargas de imágenes.
Por ultimo definimos nuestras urls. Aquí es importante distinguir entre dos archivos urls.py:
urls.py
del Proyecto: Funciona como el nivel más alto de configuración de URL, que enruta las solicitudes a las aplicaciones correspondientes usandoinclude()
.urls.py
de la Aplicación: Define rutas específicamente para los recursos y funcionalidades ofrecidas por una aplicación individual.
Con esto, editamos el archivo ImageAPI//urls.py
para que incluya lo siguiente:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('imageapp.urls')), # Incluye las rutas de la aplicación imageapp
]
Luego editamos el archivo imageapp/urls.py
de la siguiente manera:
from django.urls import path
from .views import ImageProcessView
urlpatterns = [
path('process/', ImageProcessView.as_view(), name='image-process'),
]
Aqui utilizamos la función path
para definir una ruta URL. path
toma un string que define el patrón de la URL, una vista que manejará las solicitudes a esa URL, y opcionalmente, un nombre que se puede utilizar para referenciar la URL en otras partes del código, como en las plantillas de Django.
Con todo esto listo, podemos probar nuestra API
Paso 3: Desplegar y testear
Para probar nuestra API con solicitudes desde localhost
ejecutamos:
python manage.py runserver
O alternativamente, si deseamos hacer las solicitudes desde otro dispositivo en la red:
python manage.py runserver 0.0.0.0:8000
Si este último es el caso, también debemos asegurarnos de que el dispositivo que hará las solicitudes se encuentre en la lista de ALLOWED_HOSTS
, esto lo haremos editando el archivo settings.py
del proyecto agregando:
ALLOWED_HOSTS = [DEVICE_IP, ‘localhost’, ‘127.0.0.1’]
Ahora, para efectuar una prueba, debemos enviar una imagen a nuestro servidor, para lo cual nos ayudaremos de una imágen cualquiera y el comando curl
. En la consola ejecutaremos:
curl -X POST -F “image=@PATH_TO_IMAGE.png” http://localhost:8000/api/process/
Deberíamos recibir un output similar al siguiente:
{“details”:”Processed image size: 95262 bytes”}
Con esto hemos creado una aplicación básica de Django la cual nos permite procesar imágenes en el servidor con la función process_image
.
Espero que este post te haya sido de ayuda, te envío un abrazo y nos vemos en el siguiente :)