Django vs Flask: Qual Framework Escolher?
Comparação detalhada entre Django e Flask com exemplos de código, prós e contras, e recomendações para cada tipo de projeto em Python no Brasil.
Na hora de construir uma aplicação web com Python, dois nomes dominam a conversa: Django e Flask. Ambos são excelentes, mas servem para situações diferentes. Neste artigo, a gente vai comparar os dois frameworks de forma prática, com código e recomendações claras.
Visão Geral
Django: “Batteries Included”
Django é um framework full-stack que vem com tudo que você precisa para construir uma aplicação web robusta: ORM, sistema de templates, admin, autenticação, migrations e muito mais. A filosofia é “batteries included” — ou seja, tudo vem pronto para usar.
Flask: “Microframework”
Flask é um microframework que te dá o mínimo necessário para começar e deixa você escolher as ferramentas adicionais. A filosofia é dar liberdade ao desenvolvedor para escolher cada componente.
Comparação Rápida
| Aspecto | Django | Flask |
|---|---|---|
| Tipo | Full-stack | Microframework |
| Curva de aprendizado | Mais íngreme | Mais suave |
| Flexibilidade | Opinativo | Livre |
| ORM | Incluso (Django ORM) | Opcional (SQLAlchemy) |
| Admin | Incluso | Não tem (Flask-Admin) |
| Autenticação | Inclusa | Extensões |
| Template engine | Django Templates | Jinja2 |
| Ideal para | Projetos médios/grandes | APIs, microsserviços |
Começando com Flask
Flask é famoso pela simplicidade do “Hello World”:
# app.py
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route("/")
def index():
return "Olá, Flask!"
@app.route("/api/saudacao/<nome>")
def saudacao(nome):
return jsonify({
"mensagem": f"Olá, {nome}!",
"status": "sucesso"
})
if __name__ == "__main__":
app.run(debug=True)
API REST com Flask
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
# "Banco de dados" em memória
tarefas = [
{"id": 1, "titulo": "Estudar Python", "concluida": False},
{"id": 2, "titulo": "Fazer exercícios", "concluida": True},
]
@app.route("/api/tarefas", methods=["GET"])
def listar_tarefas():
return jsonify({"tarefas": tarefas})
@app.route("/api/tarefas/<int:tarefa_id>", methods=["GET"])
def obter_tarefa(tarefa_id):
tarefa = next((t for t in tarefas if t["id"] == tarefa_id), None)
if tarefa is None:
abort(404)
return jsonify(tarefa)
@app.route("/api/tarefas", methods=["POST"])
def criar_tarefa():
if not request.json or "titulo" not in request.json:
abort(400)
nova_tarefa = {
"id": tarefas[-1]["id"] + 1 if tarefas else 1,
"titulo": request.json["titulo"],
"concluida": False,
}
tarefas.append(nova_tarefa)
return jsonify(nova_tarefa), 201
@app.route("/api/tarefas/<int:tarefa_id>", methods=["PUT"])
def atualizar_tarefa(tarefa_id):
tarefa = next((t for t in tarefas if t["id"] == tarefa_id), None)
if tarefa is None:
abort(404)
tarefa["titulo"] = request.json.get("titulo", tarefa["titulo"])
tarefa["concluida"] = request.json.get("concluida", tarefa["concluida"])
return jsonify(tarefa)
@app.route("/api/tarefas/<int:tarefa_id>", methods=["DELETE"])
def deletar_tarefa(tarefa_id):
tarefa = next((t for t in tarefas if t["id"] == tarefa_id), None)
if tarefa is None:
abort(404)
tarefas.remove(tarefa)
return jsonify({"resultado": True})
if __name__ == "__main__":
app.run(debug=True)
Estrutura de um projeto Flask
# Estrutura típica de projeto Flask
# meu_projeto/
# ├── app/
# │ ├── __init__.py # Factory do app
# │ ├── models.py # Modelos do banco
# │ ├── routes/
# │ │ ├── __init__.py
# │ │ ├── auth.py
# │ │ └── api.py
# │ ├── templates/
# │ │ └── base.html
# │ └── static/
# │ └── css/
# ├── config.py
# ├── requirements.txt
# └── run.py
# app/__init__.py - Application Factory Pattern
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app(config_name="development"):
app = Flask(__name__)
app.config.from_object(f"config.{config_name}")
db.init_app(app)
from app.routes.auth import auth_bp
from app.routes.api import api_bp
app.register_blueprint(auth_bp, url_prefix="/auth")
app.register_blueprint(api_bp, url_prefix="/api")
return app
Começando com Django
Django exige um pouco mais de setup inicial, mas entrega muita funcionalidade:
# Criando um projeto Django:
# django-admin startproject meu_projeto
# cd meu_projeto
# python manage.py startapp tarefas
# tarefas/models.py
from django.db import models
class Tarefa(models.Model):
titulo = models.CharField(max_length=200)
descricao = models.TextField(blank=True)
concluida = models.BooleanField(default=False)
criada_em = models.DateTimeField(auto_now_add=True)
atualizada_em = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-criada_em"]
verbose_name_plural = "Tarefas"
def __str__(self):
return self.titulo
Admin automático com Django
# tarefas/admin.py
from django.contrib import admin
from .models import Tarefa
@admin.register(Tarefa)
class TarefaAdmin(admin.ModelAdmin):
list_display = ["titulo", "concluida", "criada_em"]
list_filter = ["concluida", "criada_em"]
search_fields = ["titulo", "descricao"]
list_editable = ["concluida"]
# Com essas poucas linhas, você tem um painel administrativo completo!
# Acesse em: http://localhost:8000/admin/
Views e URLs com Django
# tarefas/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from .models import Tarefa
import json
def lista_tarefas(request):
tarefas = Tarefa.objects.all()
return render(request, "tarefas/lista.html", {"tarefas": tarefas})
def detalhe_tarefa(request, pk):
tarefa = get_object_or_404(Tarefa, pk=pk)
return render(request, "tarefas/detalhe.html", {"tarefa": tarefa})
# API REST simples com Django puro
@require_http_methods(["GET", "POST"])
def api_tarefas(request):
if request.method == "GET":
tarefas = list(Tarefa.objects.values(
"id", "titulo", "concluida", "criada_em"
))
return JsonResponse({"tarefas": tarefas}, safe=False)
elif request.method == "POST":
dados = json.loads(request.body)
tarefa = Tarefa.objects.create(
titulo=dados["titulo"],
descricao=dados.get("descricao", ""),
)
return JsonResponse({
"id": tarefa.id,
"titulo": tarefa.titulo,
"concluida": tarefa.concluida,
}, status=201)
# tarefas/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.lista_tarefas, name="lista_tarefas"),
path("<int:pk>/", views.detalhe_tarefa, name="detalhe_tarefa"),
path("api/", views.api_tarefas, name="api_tarefas"),
]
Django REST Framework
Para APIs REST profissionais, o Django REST Framework (DRF) é o padrão:
# pip install djangorestframework
# tarefas/serializers.py
from rest_framework import serializers
from .models import Tarefa
class TarefaSerializer(serializers.ModelSerializer):
class Meta:
model = Tarefa
fields = ["id", "titulo", "descricao", "concluida", "criada_em"]
read_only_fields = ["criada_em"]
# tarefas/views_api.py
from rest_framework import viewsets, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Tarefa
from .serializers import TarefaSerializer
class TarefaViewSet(viewsets.ModelViewSet):
queryset = Tarefa.objects.all()
serializer_class = TarefaSerializer
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ["titulo", "descricao"]
ordering_fields = ["criada_em", "titulo"]
@action(detail=False, methods=["get"])
def pendentes(self, request):
pendentes = self.queryset.filter(concluida=False)
serializer = self.get_serializer(pendentes, many=True)
return Response(serializer.data)
@action(detail=True, methods=["post"])
def concluir(self, request, pk=None):
tarefa = self.get_object()
tarefa.concluida = True
tarefa.save()
return Response({"status": "tarefa concluída"})
Django ORM vs SQLAlchemy (Flask)
Django ORM
# Consultas com Django ORM
from tarefas.models import Tarefa
from django.db.models import Count, Q
# Criar
tarefa = Tarefa.objects.create(titulo="Estudar Django")
# Buscar
todas = Tarefa.objects.all()
pendentes = Tarefa.objects.filter(concluida=False)
tarefa = Tarefa.objects.get(id=1)
# Consultas complexas
resultado = Tarefa.objects.filter(
Q(titulo__icontains="python") | Q(descricao__icontains="python"),
concluida=False
).order_by("-criada_em")[:10]
# Agregações
stats = Tarefa.objects.aggregate(
total=Count("id"),
concluidas=Count("id", filter=Q(concluida=True)),
pendentes=Count("id", filter=Q(concluida=False)),
)
SQLAlchemy com Flask
# Consultas com SQLAlchemy (Flask)
from app import db
class Tarefa(db.Model):
id = db.Column(db.Integer, primary_key=True)
titulo = db.Column(db.String(200), nullable=False)
concluida = db.Column(db.Boolean, default=False)
# Criar
tarefa = Tarefa(titulo="Estudar Flask")
db.session.add(tarefa)
db.session.commit()
# Buscar
todas = Tarefa.query.all()
pendentes = Tarefa.query.filter_by(concluida=False).all()
tarefa = Tarefa.query.get(1)
# Consultas complexas
from sqlalchemy import or_
resultado = Tarefa.query.filter(
or_(
Tarefa.titulo.ilike("%python%"),
Tarefa.descricao.ilike("%python%")
),
Tarefa.concluida == False
).order_by(Tarefa.criada_em.desc()).limit(10).all()
Quando Usar Cada Um?
Escolha Django quando:
- Você está construindo uma aplicação web completa com frontend
- Precisa de um painel admin pronto
- O projeto é médio ou grande
- Trabalha em equipe e quer convenções claras
- Precisa de autenticação de usuários
- Quer ORM, migrations e tudo integrado
- Está construindo um e-commerce, CMS ou rede social
Escolha Flask quando:
- Está construindo uma API simples ou microsserviço
- Quer total controle sobre as ferramentas
- O projeto é pequeno ou você está prototipando
- Precisa de alta customização
- Quer aprender como cada componente funciona internamente
- Está construindo algo muito específico que não se encaixa nos padrões do Django
Ou considere FastAPI
Vale mencionar que, para APIs REST em 2026, o FastAPI tem ganhado muito espaço no Brasil e no mundo. Ele oferece performance superior, documentação automática e validação de dados nativa. A gente tem um artigo completo sobre FastAPI aqui no blog.
Mercado de Trabalho no Brasil
No Brasil, o Django ainda domina o mercado de vagas para desenvolvimento web com Python, especialmente em:
- Startups e fintechs
- Empresas de tecnologia
- Órgãos governamentais
- E-commerce
Flask aparece bastante em:
- Microsserviços
- APIs internas
- Projetos de ciência de dados (dashboards)
- Prototipagem rápida
A nossa recomendação: aprenda Django primeiro se quer desenvolver para web profissionalmente. Depois, aprenda Flask para entender como as coisas funcionam “por baixo dos panos”. E não deixe de dar uma olhada no FastAPI para APIs modernas.
No fim das contas, saber os dois (ou três!) frameworks te torna um profissional mais completo e versátil. O importante é começar por um e ir expandindo seus conhecimentos conforme a necessidade.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português