DEV Community

Maximiliano Burgos
Maximiliano Burgos

Posted on

Diario de Python | #9. Color Choice: Volantazo

Este diario es el fruto de mis confesiones técnicas, y aca va una: estuve inmerso en el curso de desarrollo web con Python y Django; y esto me alejó de FastAPI, al menos por un tiempo.

Además encontré en Django una forma más robusta de trabajar, tanto en una web con su frontend como en la API que puede exponer con sus métodos y sus serializadores.

Refactor del Proyecto

Por un lado, borré las carpetas y dependencias de FastAPI y las reemplacé por las de Django y DRF (Django Rest Framework). Pueden acceder al proyecto final en mi repositorio.

Por otro, armé una app llamada "api", la cual contiene todos los modelos, serializers, views y demás.

Los modelos

Tanto para Vote como Color, definí ambos en models.py:

class Color(models.Model):
    name = models.CharField(max_length=10)

    def __str__(self):
        return self.name


class Vote(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, unique=True)
    color = models.ForeignKey(Color, on_delete=models.CASCADE)

    def __str__(self):
        return f"{self.user} voted to {self.color}"
Enter fullscreen mode Exit fullscreen mode

Django Admin

Para poder agregarlos mediante el admin de Django, los incluí en admin.py:

from .models import Vote, Color

admin.site.register([Vote, Color])
Enter fullscreen mode Exit fullscreen mode

Serializers

DRF tiene un componente que permite controlar la información de los modelos que devolveremos en la API. En serializers.py definí los dos que necesitaba:

from rest_framework.serializers import ModelSerializer
from .models import Vote, Color


class ColorSerializer(ModelSerializer):
    class Meta:
        model = Color


class VoteSerializer(ModelSerializer):
    class Meta:
        model = Vote
        depth = 1
Enter fullscreen mode Exit fullscreen mode

El atributo depth = 1 permite que la respuesta de Vote contenga dentro a Color. Si no ponía esta propiedad, solo devolvía el id que lo relaciona. Esto es posible por lo que definimos previamente en el modelo de Vote:

color = models.ForeignKey(Color, on_delete=models.CASCADE)
Enter fullscreen mode Exit fullscreen mode

Viewsets

Un ViewSet es una clase que agrupa lógica de vistas relacionadas en un solo lugar. Es una abstracción de alto nivel que permite definir un conjunto de vistas (GET, POST, PUT, DELETE, entre otras) para un modelo determinado con una única clase.

Posee dos atributos básicos y obligatorios, los cuales son queryset, que define los datos con los que vamos a trabajar; y serializer_class, el serializador que aplicará a los mismos.

En mi caso yo tenía dos modelos, dos serializadores, y por supuesto, necesitaba dos Viewsets:

class ColorViewSet(viewsets.ModelViewSet):
    queryset = Color.objects.all()
    serializer_class = ColorSerializer


class VoteViewSet(viewsets.ModelViewSet):
    queryset = Vote.objects.all()
    serializer_class = VoteSerializer
Enter fullscreen mode Exit fullscreen mode

Por supuesto, esto no iba a funcionar sin mapear las rutas adecuadas.

Manejo de rutas

En primer lugar creamos un objeto router, el cual servirá para registrar mediante el método register cada ruta con su ViewSet correspondiente.

Por ultimo, generamos la famosa lista urlpatterns y le pasamos router.urls, el cual contendrá el array de rutas generadas automáticamente por el ViewSet.

from rest_framework import routers
from .views import ColorViewSet, VoteViewSet


router = routers.DefaultRouter()

router.register('colors', ColorViewSet, 'colors')
router.register('votes', VoteViewSet, 'votes')

urlpatterns = router.urls
Enter fullscreen mode Exit fullscreen mode

También debemos incluir la ruta en urls.py del proyecto:

from django.urls import path, include

urlpatterns = [
    (...),
    path('api/', include('api.urls'))
]
Enter fullscreen mode Exit fullscreen mode

Mucho código, demasiados componentes

Puede que al principio asuste tanta implementación, especialmente si venís de Flask o de desarrollar APIs en otras tecnologías. Pero la realidad es que todo en Django tiene un propósito y una explicación, y voy a detallarlo ahora:

  • Los modelos son nuestra ventana a la BD, la representación más fiel a nuestro modelo de persistencia utilizando ORM.
  • Django Admin es opcional, pero me parece cómodo para no depender de implementar toda la API para poder probar la lógica de los modelos.
  • Los serializadores son muy potentes, y creeme que en este ejemplo todavía no los estoy exprimiendo. Son como un middleware entre nuestros modelos y la respuesta final en la API.
  • Los Viewsets nos van a generar todos los métodos de un CRUD sin que nosotros tengamos que hacerlo a mano.
  • Y finalmente las rutas nos van a permitir vincular todo esto.

En los próximos artículos voy a poner esto en marcha!

Top comments (0)