Django Wars [Parte 23]: Melhorando o redirect() e o urls.py

O Django Wars foi idealizado e desenvolvido no Django 1.4. Algumas funcionalidades aqui descritas podem não funcionar ou funcionar de forma diferente em outras versões do Django

Em algumas das views do projeto, utilizamos a função redirect().
Enquanto estivemos descrevendo todas as views em um único arquivo views.py, estivemos passando como parâmetros nas chamadas da função redirect() os métodos das views para as quais desejavamos redirecionar.
Neste modo, o Django pega a view, procura a url dela no arquivo urls.py e redireciona.
Porém, como mudamos tudo e agora temos várias views em vários arquivos diferentes, manter essa tática pode quebrar o projeto.
Estamos correndo o perido de sofrer de Circular Imports (imports circulares).

Isso ocorre quando um módulo A importa o módulo B, e o módulo B importa o módulo A.
No processamento Python, ocorre mais ou menos assim:
Pega o arquivo do moduloA.py e processa-o.
Neste arquivo encontra o import do moduloB.py.
Para o processamento de moduloA.py para carregar e processar o moduloB.py.
Ao processar o moduloB.py percebe que este carrega o moduloA.py.
E ai, o Python poderia entrar em loop infinito e explodir o mundo! (não tão grave assim)
Mas o que o Python faz é ver se moduloA está na memória antes de importá-lo.
Como ele está na memória, retorna para o moduloB.py o que está lá.
A bronca é que o que o Python tem naquela hora é só um pedaço do carregamento do moduloA.py.
E ai, se dentro do funcionamento de moduloB.py fizer uma chamada para algo de moduloA.py que ainda não foi carregado, PAU!

Para fugir disso, a coisa mais fácil a se fazer é alterar um pouco o funcionamento do urls.py.
O que vamos fazer é dar nomes as urls.
Na descrição do módulo django.conf.urls vemos como escrever urls bem supimpas.
Mas, para ficar de fácil entendimento como devemos proceder, vou colocar aqui o urls.py modificado.

from django.conf.urls import patterns, include, url

import djangowars.views.crimes
import djangowars.views.inventario
import djangowars.views.loja
import djangowars.views.player
import djangowars.views.site

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()


urlpatterns = patterns('',
                       url(r'^$', djangowars.views.site.index),
                       
                       url(r'^registrar/$', djangowars.views.player.registrar, name='pagina_de_registro'), # pagina de cadastro
                       url(r'^login/$', djangowars.views.player.logar, name='pagina_de_login'), # pagina de login
                       
                       url(r'^crimes/$', djangowars.views.crimes.crimes, name='pagina_de_crimes'),
                       url(r'^crimes/cometer/1/$', djangowars.views.crimes.cometer_crime1),
                       url(r'^crimes/cometer/2/$', djangowars.views.crimes.cometer_crime2),
                       
                       url(r'^loja/$', djangowars.views.loja.loja, name='pagina_da_loja'), # pagina de loja
                       url(r'^loja/comprar/armadura/(\d+)/$', djangowars.views.loja.comprar_armadura), # pagina de loja
                       url(r'^loja/vender/armadura/(\d+)/$', djangowars.views.loja.vender_armadura), # pagina de loja
                       url(r'^loja/comprar/arma/(\d+)/$', djangowars.views.loja.comprar_arma), # pagina de loja
                       url(r'^loja/vender/arma/(\d+)/$', djangowars.views.loja.vender_arma), # pagina de loja
                       
                       url(r'^inventario/$', djangowars.views.inventario.inventario, name='pagina_do_inventario'),
                       url(r'^inventario/equipar/armadura/(\d+)/$', djangowars.views.inventario.equipar_armadura),
                       url(r'^inventario/equipar/arma/(\d+)/$', djangowars.views.inventario.equipar_arma),
                       
                       
                       # Uncomment the next line to enable the admin:
                       url(r'^admin/', include(admin.site.urls)),
                       
                       # Uncomment the admin/doc line below to enable admin documentation:
                       # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
)

Notem que não dei nomes a todas as urls, apenas as urls principais (linhas 17, 18, 20, 24, 30).

Agora, para ser feliz, basta alterar as chamadas da função redirect nas views que a utilizam para, ao invés de se referenciarem através do método da view, utilizarem o nome da url.
Para elucidar o que deve ser feito, vou alterar o arquivo views/player.py

# Create your views here.
from django.shortcuts import render # funcoes de renderizacao dos templates
from django.shortcuts import redirect # Funcao para executar um http-redirect

from django.contrib.auth.forms import UserCreationForm # Formulario de criacao de usuarios
from django.contrib.auth.forms import AuthenticationForm # Formulario de autenticacao de usuarios
from django.contrib.auth import login # funcao que salva o usuario na sessao




# pagina de cadastro de jogador
def registrar(request):
    # Se dados forem passados via POST
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        
        if form.is_valid(): # se o formulario for valido
            form.save() # cria um novo usuario a partir dos dados enviados 
            return redirect(logar) # redireciona para a tela de login
        else:
            # mostra novamente o formulario de cadastro com os erros do formulario atual
            return render(request, "registrar.html", {"form": form})
    
    # se nenhuma informacao for passada, exibe a pagina de cadastro com o formulario
    return render(request, "registrar.html", {"form": UserCreationForm() })


# pagina de login do jogador
def logar(request):
    if request.method == 'POST':
        form = AuthenticationForm(data=request.POST) # Veja a documentacao desta funcao
        
        if form.is_valid():
            #se o formulario for valido significa que o Django conseguiu encontrar o usuario no banco de dados
            #agora, basta logar o usuario e ser feliz.
            login(request, form.get_user())
            return redirect("pagina_de_crimes") # redireciona o usuario logado para a pagina inicial
        else:
            return render(request, "logar.html", {"form": form})
    
    #se nenhuma informacao for passada, exibe a pagina de login com o formulario
    return render(request, "logar.html", {"form": AuthenticationForm()})

Primeiro, na parte dos imports, removi todos os imports para qualquer outra view.
Na linha 38, alterei a chamada de redirect() para receber o nome da url e não o método que recebia antes.

Notem que na linha 20 não alterei a chamada de redirect().
Como o método chamado, logar, está neste mesmo arquivo, optei por não mudar para ficar de aprendizado que o redirect() possui mais de uma forma de funcionar.

Por fim, farei as alterações em todos os outros arquivos dentro da pasta views.
Espero que vocês façam as alterações nos arquivos de vocês, ou baixem o código pronto direto de:
https://github.com/frenetic/django-wars

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *