Dominando Serializers no Django REST Framework

No ecossistema do Django REST Framework (DRF), os Serializers desempenham um papel crucial. Eles atuam como uma ponte entre objetos complexos do Python (como instâncias de modelos ou QuerySets) e formatos de dados leves, como JSON ou XML, que podem ser facilmente consumidos por front-ends ou dispositivos móveis.

Funções Principais de um Serializer

  • Serialização: Converte instâncias de modelos em dicionários Python, que posteriormente são transformados em JSON pela classe Response.
  • Desserialização: Recebe dados enviados pelo cliente (request), valida-os e os transforma em dicionários prontos para serem salvos no banco de dados como objetos.
  • Validação: Garante que os dados recebidos sigam regras específicas (comprimento, tipo, lógica de negócio) antes de qualquer persistência.

Implementação Básica

Para criar um serializer, devemos herdar da classe serializers.Serializer (ou ModelSerializer) e definir os campos que desejamos manipular.

Definindo o Serializer (serializers.py)

from rest_framework import serializers

class ProdutoSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    nome = serializers.CharField(max_length=100, min_length=2)
    preco = serializers.DecimalField(max_digits=10, decimal_places=2)
    descricao = serializers.CharField(required=False, allow_blank=True)
    
    # Campo calculado personalizado
    info_formatada = serializers.SerializerMethodField()

    def get_info_formatada(self, obj):
        return f"Produto: {obj.nome} - R$ {obj.preco}"

Utilizando na View (views.py)

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Produto
from .serializers import ProdutoSerializer

class CatalogoView(APIView):
    def get(self, request):
        # Obtendo todos os registros do banco
        lista_produtos = Produto.objects.all()
        # serializando múltiplos objetos (many=True)
        serializer = ProdutoSerializer(instance=lista_produtos, many=True)
        return Response(serializer.data)

Tipos de Campos Comuns

O DRF oferece uma vasta gama de campos para atender diferentes necessidades de dados:

Tipo de Campo Uso Comum
CharField Textos em geral, suporta validações de tamanho.
IntegerField Números inteiros.
DecimalField Valores monetários (exige max_digits e decimal_places).
DateTimeField Datas e horários.
EmailField Valida se a string é um e-mail válido.
ListField Utilizado para listas de sub-objetos.

Parâmetros de Configuração

Cada campo pode aceitar argumentos que controlam seu comportamento:

  • read_only: Se True, o campo é enviado na resposta, mas ignorado na criação/atualização.
  • write_only: Se True, o campo é recebido para salvar no banco, mas nunca é enviado de volta ao cliente (útil para senhas).
  • required: Define se o campo é obrigatório no envio dos dados.
  • default: Valor padrão caso o campo não seja fornecido.

Desserialização: Criando e Atualizando Dados

Para permitir que o serializer salve informações, precisamos implementar os métodos create e update.

class ProdutoSerializer(serializers.Serializer):
    # ... campos definidos anteriormente ...

    def create(self, validated_data):
        """Cria uma nova instância de Produto"""
        return Produto.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """Atualiza uma instância existente"""
        instance.nome = validated_data.get('nome', instance.nome)
        instance.preco = validated_data.get('preco', instance.preco)
        instance.descricao = validated_data.get('descricao', instance.descricao)
        instance.save()
        return instance

Validação com Hooks (Ganchos)

Podemos adicionar lógicas de validação personalizadas através de métodos específicos dentro da classe do serializer.

Validação de Campo Único (Local)

def validate_nome(self, value):
    if "promoção" in value.lower():
        raise serializers.ValidationError("O nome não pode conter a palavra promocional.")
    return value

Validação Global (Múltiplos Campos)

def validate(self, data):
    if data['preco'] < 0:
        raise serializers.ValidationError("O preço não pode ser negativo.")
    return data

Processo de Persistência na View

Ao lidar com requisições POST ou PUT, o fluxo segue este padrão:

def post(self, request):
    # 1. Passamos os dados da requisição para o serializer
    serializer = ProdutoSerializer(data=request.data)
    
    # 2. Validamos os dados
    if serializer.is_valid():
        # 3. Salvamos (dispara o método create ou update)
        serializer.save()
        return Response(serializer.data, status=201)
    
    return Response(serializer.errors, status=400)

Configuração de Localização

Para garantir que as mensagens de erro e formatos de data estejam corretos para o idioma local, ajuste o settings.py do seu projeto Django:

LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'America/Sao_Paulo'
USE_I18N = True
USE_L10N = True
USE_TZ = True

Tags: Django REST-Framework Python Serialization backend

Publicado em 9-21 09:14