Uso del parámetro depth en Django REST framework

El parámetro depth en Django REST framework (DRF) es una herramienta útil para controlar la profundidad de las relaciones de clave foránea que se serializan de forma automática.

Modelos de Ejemplo

Consideremos un escenario con dos modelos: User y Group, donde un usuario pertenece a un grupo (relación uno a muchos).


from django.db import models

class Group(models.Model):
   gid = models.CharField("Group ID", max_length=30, unique=True, null=False, blank=False)
   name = models.CharField("Group Name", max_length=30, unique=True, null=False, blank=False)
   created = models.DateTimeField("Creation Time", auto_now_add=True)
   updated = models.DateTimeField("Update Time", auto_now=True)

   def __str__(self):
       return self.name

class User(models.Model):
   uid = models.CharField("User ID", max_length=30, unique=True, null=False, blank=False)
   name = models.CharField("Username", max_length=30, unique=True, null=False, blank=False)
   email = models.EmailField("User Email", max_length=30, unique=True, null=False, blank=False)
   group = models.ForeignKey(
       Group,
       on_delete=models.SET_NULL,
       null=True,
       blank=True,
       related_name="users_in_group",
       db_column="group_name", # Especifica el nombre de la columna en la base de datos
       to_field="name"         # Especifica el campo del modelo Group a referenciar
   )
   created = models.DateTimeField("Creation Time", auto_now_add=True)
   updated = models.DateTimeField("Update Time", auto_now=True)

   def __str__(self):
       return self.name
   

Serializadores y el Parámetro depth

El parámetro depth se define dentro de la clase Meta de un ModelSerializer.

Caso sin depth o depth=0

Sin el parámetro depth, o con depth=0, las relaciones de clave foránea se representan por defecto con el ID del objeto relacionado o un campo específico si se define explícitamente (como se muestra en el ejemplo anterior con to_field="name"). Sin embargo, la serialización no incluirá los detalles completos del objeto relacionado.

Caso con depth=1

Al establecer depth=1, DRF serializará automáticamente los campos del modelo relacionado (Group en este caso) una vez. Esto significa que al obtener un objeto User, la información de su group se mostrará en detalle en lugar de solo una referencia.


from rest_framework import serializers
from .models import User, Group

class GroupSerializer(serializers.ModelSerializer):
   class Meta:
       model = Group
       fields = '__all__'

class UserSerializerWithDepth(serializers.ModelSerializer):
   class Meta:
       model = User
       fields = '__all__'
       depth = 1
   

Impacto de depth:

  • Lectura (GET): Con depth > 0, las claves foráneas se expanden para mostrar los campos del modelo relacionado hasta la profundidad especificada.
  • Escritura (POST, PUT, PATCH): Cuando se usa depth, DRF no permite directamente la creación o actualización de objetos a través de la clave foránea expandida. Se espera un identificador (como el ID o el campo especificado en to_field) en la solicitud de entrada.

Manejo de Creación/Actualización con depth

Si se desea la conveniencia de ver los detalles del objeto relacionado (depth=1) pero también poder crear o actualizar objetos pasando la información completa de la relación, es necesario un enfoque más personalizado. Esto generalmente implica sobrescribir el método get_serializer_class en el ViewSet para usar diferentes serializadores para operaciones de lectura y escritura.

Serializadores Modificados


from rest_framework import serializers
from .models import User, Group

class GroupSerializer(serializers.ModelSerializer):
   class Meta:
       model = Group
       fields = '__all__'

class UserDetailSerializer(serializers.ModelSerializer): # Serializador para mostrar detalles
   class Meta:
       model = User
       fields = '__all__'
       depth = 1

class UserCreateUpdateSerializer(serializers.ModelSerializer): # Serializador para creación/actualización
   class Meta:
       model = User
       fields = '__all__'
       # depth no se usa aquí, o se podría establecer en 0
   

Vista (View) Personalizada


from rest_framework import viewsets
from .models import User, Group
from .serializers import UserDetailSerializer, UserCreateUpdateSerializer, GroupSerializer

class UserViewSet(viewsets.ModelViewSet):
   queryset = User.objects.all()
   # El serializador por defecto para operaciones de lectura
   serializer_class = UserDetailSerializer

   def get_serializer_class(self):
       if self.action in ['create', 'update', 'partial_update']:
           # Usar un serializador diferente para operaciones de escritura
           return UserCreateUpdateSerializer
       # Para otras acciones (como 'list', 'retrieve'), usar el serializador con depth
       return UserDetailSerializer

class GroupViewSet(viewsets.ModelViewSet):
   queryset = Group.objects.all()
   serializer_class = GroupSerializer
   

Este patrón permite que las solicitudes GET devuelvan la información detallada del grupo asociado al usuario, mientras que las solicitudes POST, PUT o PATCH esperan solo el identificador del grupo (o el campo especificado en to_field) para realizar la operación.

Etiquetas: Django REST Framework DRF serialization foreign keys depth

Publicado el 8-28 13:52