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 ento_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.