O Fluxo de Vida de uma Requisição
O ciclo de vida de uma requisição no Django descreve toda a jornada que um pedido do usuário perocrre desde o navegador até a geração da resposta final pelo servidor. Compreender esse fluxo é fundamental para arquitetar aplicações eficientes.
Quando uma requisição HTTP chega, ela é recebida pela interface WSGI. O Django utiliza o wsgiref como servidor de desenvolvimento embutido, mas por suas limitações de concorrência, ambientes de produção exigem servidores como uWSGI ou Gunicorn. É importante notar que WSGI é o protocolo de comunicação, enquanto wsgiref e uWSGI são as implementações práticas desse protocolo.
A sequência de processamento interno segue a seguinte ordem:
- Middleware: Atua como uma camada de interceptação (semelhante a um firewall ou segurança), validando e processando dados tanto na entrada quanto na saída.
- Camada de Rotas (URL Dispatcher): Analisa o caminho da URL e determina qual função de visão (view) deve ser executada.
- Camada de Visão (Views): Contém a lógica de negócios. Recebe a requisição, interage com a camada de modelos para buscar ou salvar dados no banco de dados e renderiza a resposta.
- Camada de Modelos (Models): Define a estrutura do banco de dados e fornece a API ORM para interação com os dados.
- Camada de Templates: Responsável por gerar o HTML dinâmico que será retornado ao cliente.
Camada de Roteamento (URL Dispatcher)
Correspondência de Rotas
Nas versões modernas do Django (2.0 e superiores), a função path() é utilizada para correspondência exata de strings. Em versões mais antigas (1.x), utilizava-se a função url(), que dependia exclusivamente de expressões regulares.
Por padrão, o Django possui um mecanismo que adiciona automaticamente uma barra invertida (/) ao final das URLs que não a possuem, redirecionando o usuário. Esse comportamento é controlado pela variável APPEND_SLASH no arquivo de configurações:
# settings.py
# Defina como False para desativar o redirecionamento automático de barras
APPEND_SLASH = False
Conversores de Rota Dinâmica
Para lidar com URLs que contêm variáveis (como IDs de usuários ou slugs de artigos), o Django 2.0+ introduziu os conversores de rota. Eles permitem capturar partes da URL e convertê-las para tipos de dados específicos antes de passá-las para a view.
Os conversores nativos incluem:
str: Captura qualquer string não vazia, excluindo o caractere de barra (/).int: Captura e converte para zero ou inteiros positivos.slug: Captura strings compostas por letras, números, hifens e underscores.uuid: Captura strings formatadas como UUID.path: Captura qualquer string, incluindo barras (útil para caminhos completos).
from django.urls import path
from . import views
urlpatterns = [
# Captura um slug de categoria e um ID inteiro de produto
path('loja/<categoria>/item/<produto_id>/', views.detalhe_produto),
]
# A view receberá os argumentos tipados:
# def detalhe_produto(request, categoria, produto_id):
</produto_id></categoria>
Correspondência por Expressões Regulares
Quando a lógica de correspondência exige padrões mais complexos que os conversores nativos não suportam, utiliza-se a função re_path() (ou url() no Django 1.x).
Um detalhe crucial em expressões regulares é o uso da barra invertida no final do padrão. Se omitida, a correspondência pode ocorrer em qualquer parte da URL que satisfaça a regex. Se incluída ($), garante que a URL termine exatamente naquele ponto.
Grupos Sem Nome (Posicionais)
Ao usar parênteses () sem definir um nome, o valor capturado é passado para a view como um argumento posicional.
from django.urls import re_path
from . import views
urlpatterns = [
# Captura ano e mês como argumentos posicionais
re_path(r'^relatorios/(\d{4})/(\d{2})/$', views.relatorio_mensal),
]
# Definição da view:
# def relatorio_mensal(request, ano, mes):
Grupos Com Nome (Keyword Arguments)
Utilizando a sintaxe (?P<nome>padrao), os valores capturados são passados como argumentos nomeados (kwargs). Atenção: Não é possível misturar grupos com nome e sem nome na mesma expressão regular.
urlpatterns = [
# Captura ano e mes como argumentos nomeados
re_path(r'^relatorios/(?P<ano>\d{4})/mes/(?P<mes>\d{2})/$', views.relatorio_mensal),
]
# Definição da view:
# def relatorio_mensal(request, ano, mes):
Resolução Reversa de URLs
Hardcodar URLs em templates ou views (como /loja/camisa/item/5/) gera um forte acoplamento. Se a estrutura da rota mudar, todos os links quebrarão. A resolução reversa permite gerar URLs dinamicamente baseando-se no nome da rota.
Configuração e Uso
Primeiro, atribua um atributo name à sua rota:
path('perfil/<username>/', views.ver_perfil, name='user_profile')
</username>
No backend (Python), utilize a função reverse:
from django.shortcuts import reverse
# Gera a URL: /perfil/john_doe/
url_gerada = reverse('user_profile', kwargs={'username': 'john_doe'})
No frontend (Templates HTML), utilize a tag url:
<a href="{% url 'user_profile' 'john_doe' %}">Ver Perfil</a>
Distribuição de Rotas (Include)
Em projetos modulares, manter todas as rotas em um único arquivo urls.py torna o código ilegível e difícil de manter. O Django resolve isso através da função include(), que delega a responsabilidade de roteamento para os arquivos de URL específicos de cada aplicativo.
# urls.py do projeto principal (raiz)
from django.urls import path, include
urlpatterns = [
path('api/vendas/', include('vendas.urls')),
path('api/inventario/', include('inventario.urls')),
]
Dessa forma, o roteador principal apenas identifica o prefixo e encaminha o restante da URL para o módulo correspondente, promovendo o desacoplamento total entre as aplicações.
Namespaces (Espaços de Nomes)
Ao utilizar distribuição de rotas, pode ocorrer um conflito de nomes: dois aplicativos diferentes podem ter uma rota chamada name='detail'. Para evitar que a resolução reversa aponte para a URL errada, utilizamos namespaces.
Implementação via Namespace
Defina o namespace ao incluir as URLs no roteador principal:
# urls.py principal
urlpatterns = [
path('blog/', include('blog.urls', namespace='blog')),
path('forum/', include('forum.urls', namespace='forum')),
]
No arquivo de URLs do aplicativo, defina a variável app_name:
# blog/urls.py
app_name = 'blog'
urlpatterns = [
path('post/<id>/', views.post_detail, name='detail'),
]
</id>
Agora, a resolução reversa exige o prefixo do namespace:
# Backend
reverse('blog:detail', kwargs={'id': 42})
# Template
{% url 'blog:detail' 42 %}
Alternativa: Nomes Únicos
Se o uso de namespaces não for desejado, a alternativa é garantir a unicidade dos nomes das rotas, geralmente prefixando-os com o nome do aplicativo:
path('post/<id>/', views.post_detail, name='blog_post_detail')
path('topico/<id>/', views.topico_detail, name='forum_topico_detail')
</id></id>