Gerenciamento de Rotas no Django

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 name para 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 ^artigos em vez de ^/artigos.
  • O prefixo r antes 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 urlpatterns na 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, chamando views.arquivos_por_mes(request, '2005', '03').
  • /artigos/2003/ corresponderá ao primeiro padrão, não ao segundo, devido à ordem de processamento.
  • /artigos/2003 não corresponderá a nenhum padrão, pois todos exigem uma barra final.
  • /artigos/2003/03/03/ corresponderá ao último padrão, chamando views.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>

Tags: Django Python Routing urls Web Development

Publicado em 8-7 03:23