Serialización de Datos
La serialización convierte objetos Python en formatos como JSON para transmisión HTTP, mientras que la deserialización hace el proceso inverso.
Serializer Básico
# serializers.py
from rest_framework import serializers
from .models import Usuario, Post
class UsuarioSerializer(serializers.ModelSerializer):
posts_count = serializers.SerializerMethodField()
avatar_url = serializers.SerializerMethodField()
class Meta:
model = Usuario
fields = ['id', 'username', 'email', 'first_name', 'last_name',
'fecha_registro', 'posts_count', 'avatar_url']
read_only_fields = ['id', 'fecha_registro']
def get_posts_count(self, obj):
return obj.posts.count()
def get_avatar_url(self, obj):
if obj.avatar:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.avatar.url)
return None
def validate_email(self, value):
if Usuario.objects.filter(email=value).exists():
raise serializers.ValidationError("Este email ya está en uso")
return value
class PostSerializer(serializers.ModelSerializer):
autor = UsuarioSerializer(read_only=True)
comentarios_count = serializers.SerializerMethodField()
class Meta:
model = Post
fields = ['id', 'titulo', 'contenido', 'autor', 'fecha_creacion',
'fecha_actualizacion', 'comentarios_count']
def get_comentarios_count(self, obj):
return obj.comentarios.count()
Serializer Anidado
# Serializers con relaciones anidadas
class ComentarioSerializer(serializers.ModelSerializer):
autor = serializers.StringRelatedField()
class Meta:
model = Comentario
fields = ['id', 'contenido', 'autor', 'fecha_creacion']
class PostDetalleSerializer(serializers.ModelSerializer):
autor = UsuarioSerializer(read_only=True)
comentarios = ComentarioSerializer(many=True, read_only=True)
etiquetas = serializers.StringRelatedField(many=True)
class Meta:
model = Post
fields = ['id', 'titulo', 'contenido', 'autor', 'fecha_creacion',
'fecha_actualizacion', 'comentarios', 'etiquetas']
def create(self, validated_data):
validated_data['autor'] = self.context['request'].user
return super().create(validated_data)
Filtrado de Datos
El filtrado permite a los clientes especificar criterios para obtener subconjuntos específicos de datos.
Filtros con django-filter
# filters.py
import django_filters
from .models import Post, Usuario
class PostFilter(django_filters.FilterSet):
titulo = django_filters.CharFilter(lookup_expr='icontains')
autor = django_filters.ModelChoiceFilter(queryset=Usuario.objects.all())
fecha_desde = django_filters.DateFilter(field_name='fecha_creacion', lookup_expr='gte')
fecha_hasta = django_filters.DateFilter(field_name='fecha_creacion', lookup_expr='lte')
contenido = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Post
fields = ['titulo', 'autor', 'fecha_desde', 'fecha_hasta', 'contenido']
# views.py
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_class = PostFilter
search_fields = ['titulo', 'contenido', 'autor__username']
ordering_fields = ['fecha_creacion', 'titulo']
ordering = ['-fecha_creacion']
Filtros Personalizados
# Filtros personalizados en ViewSets
class PostViewSet(viewsets.ModelViewSet):
serializer_class = PostSerializer
def get_queryset(self):
queryset = Post.objects.all()
# Filtro por autor
autor_id = self.request.query_params.get('autor', None)
if autor_id:
queryset = queryset.filter(autor_id=autor_id)
# Filtro por popularidad
popular = self.request.query_params.get('popular', None)
if popular == 'true':
queryset = queryset.annotate(
comentarios_count=Count('comentarios')
).filter(comentarios_count__gte=5)
# Filtro por rango de fechas
fecha_desde = self.request.query_params.get('fecha_desde', None)
fecha_hasta = self.request.query_params.get('fecha_hasta', None)
if fecha_desde:
queryset = queryset.filter(fecha_creacion__gte=fecha_desde)
if fecha_hasta:
queryset = queryset.filter(fecha_creacion__lte=fecha_hasta)
return queryset.select_related('autor').prefetch_related('comentarios')