Popular Django com dados brasileiros
Popular Django com dados brasileiros: seed do ORM com CPF, CNPJ e PIX
Publicado em 2026-09-24 · Leitura ~10 min
Se você tá construindo app Django que atende Brasil, seed de banco com dado real de produção não é opção. LGPD proíbe, DPO não deixa, e mesmo se deixasse, cópia de produção pra staging é receita pra vazamento. A rota certa é popular staging com dados brasileiros sintéticos válidos. Este guia mostra 3 abordagens, código pronto pra copiar, e quando cada uma faz sentido.
O problema real: por que Faker sozinho não resolve
Faker Python com locale pt_BR gera nome, email, endereço, telefone e alguns documentos. Mas tem 3 furos graves:
- CPF quebra validação mod-11 em alguns cenários. Se seu Django tem validator (comum via
cpf-cnpj-validatorou similar), Faker pode gerar CPF que quebra em CI. - Zero correlação entre campos. Faker gera nome "João Silva" com email "jane@doe.com" e telefone com DDD 61 (DF), enquanto o endereço tá em São Paulo. Se seu app tem antifraude que valida coerência, teste dispara falso positivo em toda rodada.
- Sem cartão de crédito válido, PIX BACEN, conta bancária real. Faker gera número random. Se você testa integração com gateway ou validador Luhn, quebra.
Abordagem 1: Faker + validators manuais
Se você só precisa cobrir o básico e não quer dependência externa, escreve validator próprio. Aqui vai o mod-11 pra CPF em ~30 linhas:
# utils/generators.py
import random
def gerar_cpf() -> str:
"""Gera CPF válido pelo mod-11 da Receita Federal."""
n = [random.randint(0, 9) for _ in range(9)]
# Primeiro dígito
s = sum(a * b for a, b in zip(n, range(10, 1, -1)))
d1 = (s * 10) % 11
d1 = 0 if d1 == 10 else d1
n.append(d1)
# Segundo dígito
s = sum(a * b for a, b in zip(n, range(11, 1, -1)))
d2 = (s * 10) % 11
d2 = 0 if d2 == 10 else d2
n.append(d2)
return f"{n[0]}{n[1]}{n[2]}.{n[3]}{n[4]}{n[5]}.{n[6]}{n[7]}{n[8]}-{n[9]}{n[10]}"Combina com Faker no seu comando de management:
# myapp/management/commands/seed_staging.py
from django.core.management.base import BaseCommand
from faker import Faker
from myapp.models import Customer
from utils.generators import gerar_cpf
class Command(BaseCommand):
def handle(self, *args, **options):
fake = Faker("pt_BR")
Customer.objects.bulk_create([
Customer(
nome=fake.name(),
cpf=gerar_cpf(),
email=fake.email(),
telefone=fake.phone_number(),
cep=fake.postcode(),
)
for _ in range(1000)
])
self.stdout.write(f"1000 clientes seeded")Roda com python manage.py seed_staging.
Quando usar: app simples, sem correlação, sem PIX, sem cartão. Cobre 40% dos casos.
Limitação: mesmo com CPF válido, os campos são independentes. Email não deriva do nome. DDD do telefone é aleatório vs UF. Pra teste de fluxo real, isso quebra.
Abordagem 2: python-brasilidades pra CPF/CNPJ, Faker pro resto
A biblioteca python-brasilidades cobre CPF, CNPJ, CNH e RG válidos em Python puro. Instala:
pip install python-brasilidadesUso combinado:
from brasilidades.documentos import cpf, cnpj
from faker import Faker
from myapp.models import Customer
fake = Faker("pt_BR")
for _ in range(1000):
Customer.objects.create(
nome=fake.name(),
cpf=cpf.gerar(),
cnpj=cnpj.gerar(),
email=fake.email(),
telefone=fake.phone_number(),
cep=fake.postcode(),
)Quando usar: precisa CPF/CNPJ/CNH/RG válidos sem chamar API externa. Zero deps runtime além do pip install. Cobre 60% dos casos.
Limitação: continua sem correlação entre campos. Sem cartão de crédito com Luhn. Sem chave PIX BACEN. Sem conta bancária com DV real por banco.
Abordagem 3: FakeForge com presets correlacionados
O FakeForge tem SDK Python oficial que cobre todos os documentos + correlação entre campos + presets verticais. Instala:
pip install fakeforge-brSeed de 1000 clientes correlacionados em 1 chamada:
# myapp/management/commands/seed_staging.py
from django.core.management.base import BaseCommand
from fakeforge import FakeForge
from myapp.models import Customer
class Command(BaseCommand):
def handle(self, *args, **options):
ff = FakeForge(api_key="sua_key_opcional")
# 1000 clientes com CPF + email + endereço + telefone COERENTES
dados = ff.preset("customer", 1000)
Customer.objects.bulk_create([
Customer(
nome=c["nome"],
cpf=c["cpf"],
email=c["email"], # deriva do nome
telefone=c["telefone"], # DDD bate com UF
cep=c["endereco"]["cep"],
cidade=c["endereco"]["cidade"],
estado=c["endereco"]["estado"],
)
for c in dados
])
self.stdout.write(f"1000 clientes seeded (correlacionados)")Vantagem principal: email deriva do nome (Marina Silva → marina.silva@gmail.com). DDD do telefone bate com UF do endereço. Se seu Django tem antifraude que valida "email match name" ou "phone UF match address", passa no teste.
Se você constrói fintech, existe preset dedicado que devolve bundle completo:
clientes = ff.preset("fintech", 100)
# cada cliente tem:
# - customer (nome, cpf, email, telefone, endereço, renda_mensal, score_serasa)
# - pix_keys (3-4 chaves: CPF + email + phone + aleatória)
# - bank_account (17 bancos brasileiros com DV real)
# - credit_card (Luhn válido, brand random, holder = nome)Se você constrói ecommerce, tem preset ecom que devolve pedido completo com carrinho, endereços shipping/billing, payment (cartão/PIX/boleto) e totais calculados.
Quando usar: precisa dado correlacionado, cartão com Luhn, PIX BACEN, conta bancária real, presets verticais. Cobre 90% dos casos.
Limitação: requer conexão internet (chama endpoint HTTP). Free tier libera 50 chamadas/dia sem cadastro. Plano Dev R$29/mês libera 10.000 chamadas/dia com até 10.000 items por chamada.
Comparação: qual escolher
| Cenário | Faker+ util | python-brasilidades | FakeForge |
|---|---|---|---|
| App CRUD simples | ✅ | ✅ | ✅ |
| Fintech (PIX+banco+cartão) | ❌ | ❌ | ✅ |
| E-commerce (carrinho+payment) | ❌ | ❌ | ✅ |
| Antifraude (correlação obrigatória) | ❌ | ❌ | ✅ |
| 100% offline | ✅ | ✅ | ❌ |
| Seed rápido de 10k rows | ⚠️ lento | ⚠️ lento | ✅ 1 chamada |
| CNPJ alfanumérico 2026 | ❌ | ❌ | ✅ |
| Custo mensal | R$0 | R$0 | R$0-79 |
Boas práticas independente da abordagem
- Nunca seed em production database. Command management só roda em
DEBUG=Trueou com flag explícita--force-productionque você nunca vai passar por engano. - Bulk create sempre. Um
create()por row em loop é 100x mais lento quebulk_create(). Pra 10k rows, diferença é 5 min vs 3 segundos. - Reset periódico. Cron diário limpa staging + reload de dado sintético fresh. Evita LGPD gray area de "quanto tempo pode ficar dado real em staging" (não pode ter dado real em staging).
- Documenta no README. "Dados sintéticos gerados via [ferramenta]. Nenhum documento pertence a pessoa real. Uso restrito a ambiente de desenvolvimento." Protege time em auditoria LGPD.
- Cachea em CI. Se chama API externa (FakeForge), gera 1x, salva JSON em fixture, reusa entre runs. Não precisa chamar API a cada job.
Exemplo completo: seed com 10k clientes fintech
# myapp/management/commands/seed_fintech.py
from django.core.management.base import BaseCommand
from django.conf import settings
from fakeforge import FakeForge
from myapp.models import Customer, PixKey, BankAccount, CreditCard
class Command(BaseCommand):
def handle(self, *args, **options):
if not settings.DEBUG and "--force" not in options:
self.stdout.write("Refuso rodar em production. Use --force se souber.")
return
ff = FakeForge(api_key=settings.FAKEFORGE_KEY)
dados = ff.preset("fintech", 10000)
customers, pix_keys, accounts, cards = [], [], [], []
for d in dados:
c = Customer(
nome=d["customer"]["nome"],
cpf=d["customer"]["cpf"],
email=d["customer"]["email"],
telefone=d["customer"]["telefone"],
renda_mensal=d["customer"]["renda_mensal"],
score_serasa=d["customer"]["score_serasa"],
)
customers.append(c)
for pk in d["pix_keys"]:
pix_keys.append(PixKey(tipo=pk["type"], valor=pk["value"]))
ba = d["bank_account"]
accounts.append(BankAccount(
banco=ba["bankName"], agencia=ba["agency"],
conta=ba["account"], dv=ba["accountDigit"],
))
cc = d["credit_card"]
cards.append(CreditCard(
numero=cc["number"], titular=cc["holder"],
validade=cc["expiry"], cvv=cc["cvv"], bandeira=cc["brand"],
))
Customer.objects.bulk_create(customers)
PixKey.objects.bulk_create(pix_keys)
BankAccount.objects.bulk_create(accounts)
CreditCard.objects.bulk_create(cards)
self.stdout.write(f"{len(customers)} clientes fintech seeded")Roda em 8-12 segundos (1 chamada HTTP + bulk creates). Mesmo seed com Faker + validators manuais levaria 5-10 minutos.
Conclusão
Se seu Django simples só precisa CPF/CNPJ, Faker + validator manual resolve. Se precisa cobrir também cartão, PIX, banco e correlação entre campos, python-brasilidades resolve parte e FakeForge resolve tudo. Escolha baseado no que você precisa hoje, não no que pode precisar depois.
Todos os 3 são MIT-licensed ou tier gratuito honesto. Todos passam validação matemática. A diferença tá em cobertura + correlação. Meu voto: começa com python-brasilidades se app é simples, migra pra FakeForge quando precisar dos presets verticais.