O Papel do Gerenciamento de Rotas no Django
A configuração de URLs (URLconf) no Django funciona como um índice para o site. Essencialmente, ela estabelece um mapeamento entre os endereços web (URLs) e as funções de visualização (views) que devem ser executadas para cada um. Isso instrui o Django sobre qual lógica de código acionar em resposta a uma requisição de URL específica do cliente.
Um exemplo típico:
from django.urls import path
urlpatterns = [
path('artigos', views.acao_especial),
]
# O endereço 'artigos' está associado à função 'acao_especial' no módulo de views.
# Ao acessar este link no navegador, a função 'acao_especial' será executada.
Configuração Básica de Rotas
A estrutura fundamental para definir rotas no Django envolve uma lista chamada urlpatterns:
from django.urls import re_path
from meu_app import views
urlpatterns = [
re_path(r'^artigos/2003/$', views.caso_especial_2003),
re_path(r'^artigos/([0-9]{4})/$', views.arquivos_por_ano),
re_path(r'^artigos/([0-9]{4})/([0-9]{2})/$', views.arquivos_por_mes),
re_path(r'^artigos/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.detalhe_artigo),
]
- Expressão Regular: Uma string que define o padrão da URL a ser correspondida.
- Função de Visualização: Um objeto chamável (geralmente uma função de view) ou uma string especificando o caminho para a função.
- Argumentos Opcionais: Parâmetros padrão a serem passados para a função de visualização (em formato de dicionário).
- Nome Opcioanl (Alias): Um parâmetro
namepara dar um nome à rota, facilitando a referência.
Observações importantes:
- Para capturar um valor da URL, envolva-o com parênteses
(). - Não é necessário adicionar uma barra
/inicial, pois cada URL já a possui. Use^artigosem vez de^/artigos. - O prefixo
rantes da string da expressão regular indica uma string "bruta", evitando a necessidade de escapar caracteres especiais. É recomendado seu uso. - O Django processa os elementos em
urlpatternsna ordem em que são definidos. A primeira correspondência bem-sucedida encerra a busca.
Exemplos de correspondência:
/artigos/2005/03/corresponderá ao terceiro padrão, chamandoviews.arquivos_por_mes(request, '2005', '03')./artigos/2003/corresponderá ao primeiro padrão, não ao segundo, devido à ordem de processamento./artigos/2003não corresponderá a nenhum padrão, pois todos exigem uma barra final./artigos/2003/03/03/corresponderá ao último padrão, chamandoviews.detalhe_artigo(request, '2003', '03', '03').
APPEND_SLASH
A configuração APPEND_SLASH no arquivo settings.py controla se o Django deve adicionar automaticamente uma barra / ao final de URLs que não a possuem. Por padrão, APPEND_SLASH é definido como True.
Por exemplo, se você definir a rota:
from django.urls import re_path
from meu_app import views
urlpatterns = [
re_path(r'^blog/$', views.pagina_blog),
]
Acessar http://www.exemplo.com/blog será automaticamente redirecionado para http://www.exemplo.com/blog/. Se APPEND_SLASH for definido como False, a requisição para http://www.exemplo.com/blog resultaria em um erro de página não encontrada.
Grupos Nomeados (Named Groups)
Expressões regulares suportam grupos nomeados para capturar partes da URL e passá-las como argumentos nomeados para as funções de visualização. A sintaxe é (?P<nome>padrão).
Reescrevendo a configuração de URL anterior com grupos nomeados:
from django.urls import re_path
from meu_app import views
urlpatterns = [
re_path(r'^artigos/2003/$', views.caso_especial_2003),
re_path(r'^artigos/(?P<ano>[0-9]{4})/$', views.arquivos_por_ano),
re_path(r'^artigos/(?P<ano>[0-9]{4})/(?P<mes>[0-9]{2})/$', views.arquivos_por_mes),
re_path(r'^artigos/(?P<ano>[0-9]{4})/(?P<mes>[0-9]{2})/(?P<dia>[0-9]{2})/$', views.detalhe_artigo),
]
Os valores capturados são do tipo string. É possível definir valores padrão nos argumentos da função de visualização:
# Em views.py
from django.http import HttpResponse
def acao_blog(request, numero_pagina=1):
print(numero_pagina)
return HttpResponse('Ok')
# Em urls.py
from django.urls import re_path
from meu_app import views
urlpatterns = [
re_path(r'^blog/$', views.acao_blog), # Sem numero_pagina especificado
re_path(r'^blog/(?P<numero_pagina>[0-9]{1})/$', views.acao_blog), # Com numero_pagina
]
Isso resulta em chamadas como:
/artigos/2005/03/chamaráviews.arquivos_por_mes(request, ano='2005', mes='03')./artigos/2003/03/03/chamaráviews.detalhe_artigo(request, ano='2003', mes='03', dia='03').
O uso de grupos nomeados torna o urls.py mais legível e reduz a probabilidade de erros relacionados à ordem dos parâmetros.
Distribuição de Rotas (URL Routing Dispatch)
Para projetos maiores, é comum dividir a configuração de URLs em múltiplos arquivos, um para cada aplicação (app). Isso é feito usando a função include.
# urls.py principal do projeto
from django.urls import path, include
urlpatterns = [
path('app_um/', include('app_um.urls')),
path('app_dois/', include('app_dois.urls')),
]
E o arquivo app_um/urls.py:
# app_um/urls.py
from django.urls import re_path
from . import views
urlpatterns = [
re_path(r'^acao/$', views.acao_app_um),
]
Isso permite que as URLs /app_um/acao/ sejam gerenciadas pelo arquivo app_um/urls.py.
Resolução Reversa de URLs (Reverse URL Resolution)
A resolução reversa de URLs permite gerar URLs dinamicamente com base nos nomes definidos em urls.py. Isso é crucial para evitar URLs codificadas menualmente, que são difíceis de manter e propensas a erros.
Em urls.py, defina um nome para a rota:
# app_um/urls.py
from django.urls import re_path
from . import views
urlpatterns = [
re_path(r'^acao/(?P<id_item>[0-9]+)/$', views.detalhe_item, name='detalhe_item_app_um'),
]
No template HTML, use a tag url:
<a href="{% url 'detalhe_item_app_um' id_item=123 %}">Ver Detalhes</a>
No código Python (views):
# views.py
from django.shortcuts import reverse, HttpResponse
def alguma_view(request):
url_gerada = reverse('detalhe_item_app_um', args=(456,))
print(url_gerada) # Saída: '/app_um/acao/456/'
return HttpResponse('Ok')
Ao nomear suas URLs, prefixe-as com o nome da aplicação para evitar conflitos de nomes (ex: app_um-detalhe_item em vez de apenas detalhe_item).
Namespaces (Namespaces)
Namespaces ajudam a evitar conflitos de nomes quando diferentes aplicações definem rotas com o mesmo nome. Eles criam um escopo para os nomes das URLs.
No arquivo urls.py principal, ao incluir as URLs das aplicações, especifique o namespace:
# urls.py principal do projeto
from django.urls import path, include
urlpatterns = [
path('app_um/', include(('app_um.urls', 'app_um'), namespace='app_um')),
path('app_dois/', include(('app_dois.urls', 'app_dois'), namespace='app_dois')),
]
Agora, ao referenciar uma URL, você deve prefixar o nome com o namespace:
# views.py
from django.shortcuts import reverse, HttpResponse
def alguma_view(request):
url_app_um = reverse('app_um:nome_da_rota_em_app_um')
url_app_dois = reverse('app_dois:nome_da_rota_em_app_dois')
print(url_app_um)
print(url_app_dois)
return HttpResponse('Ok')
No template HTML:
<a href="{% url 'app_um:nome_da_rota_em_app_um' %}">Link App Um</a>
<a href="{% url 'app_dois:nome_da_rota_em_app_dois' %}">Link App Dois</a>
Uso de path
Introduzido no Django 2.0, o módulo path oferece uma sintaxe mais limpa e flexível para definir rotas, especialmente para o tratamento de tipos de parâmetros.
Exemplo:
from django.urls import path
from . import views
urlpatterns = [
path('artigos/2003/', views.caso_especial_2003),
path('artigos/<ano>/', views.arquivos_por_ano), # Captura um inteiro para 'ano'
path('artigos/<ano>/<mes>/', views.arquivos_por_mes), # Captura inteiros para 'ano' e 'mes'
path('artigos/<titulo>/', views.detalhe_artigo_por_titulo), # Captura um slug para 'titulo'
path('pedido/<codigo_pedido>/', views.detalhes_pedido),
]
</codigo_pedido></titulo></mes></ano></ano>
Regras básicas:
- Use chaves
<>para capturar valores da URL. - Inclua um tipo de conversor antes do nome (ex:
<int:nome>). Sem um conversor, ele corresponde a qualquer string não vazia (exceto/). - Não é necessário adicionar a barra
/inicial.
Conversores de Caminho (Path Converters)
O Django oferece conversores padrão:
str: Corresponde a qualquer string não vazia (padrão).int: Corresponde a inteiros positivos (incluindo zero).slug: Corresponde a letras, números e hifens/sublinhados.uuid: Corresponde a UUIDs formatados.path: Corresponde a qualquer string não vazia, incluindo barras/.
Registrando Conversores Personalizados
Você pode definir seus próprios conversores para necessidades específicas.
# converters.py
class FourDigitYearConverter:
regex = r'[0-9]{4}' # Padrão regex para 4 dígitos
def to_python(self, value):
# Converte o valor capturado em um inteiro Python
return int(value)
def to_url(self, value):
# Converte um valor Python de volta para uma string de URL
return f'{value:04d}' # Garante 4 dígitos com preenchimento de zero
# urls.py
from django.urls import register_converter, path
from . import converters, views
register_converter(converters.FourDigitYearConverter, 'aaaa') # Registra o conversor com o nome 'aaaa'
urlpatterns = [
path('artigos/<ano>/', views.arquivos_por_ano),
# ... outras rotas
]
</ano>