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