Django Wars [Parte 15]: Compra e venda de itens na loja

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

No artigo anterior, criamos a página da loja, onde o usuário consegue ver uma listagem dos itens que a loja possui com a opção de comprar ou vender itens.
Agora, precisamos programar as ações da loja.
Ou seja, precisamos implementar a compra e a venda de itens.

No arquivo loja.html, no artigo anterior, definimos os links de compra e de venda de itens.

<div class="container">
   <p>Armaduras:</p>
   {% for armadura in armaduras %}
       <img src="{{ armadura.imagem.url }}" />
       {{ armadura.nome }}
 
       {% if armadura in player.armaduras.all %}
           <a href="vender/armadura/{{ armadura.pk }}">vender por {{ armadura.venda }}</a>
       {% else %}
           <a href="comprar/armadura/{{ armadura.pk }}">comprar por {{ armadura.compra }}</a>
       {% endif %}
       <br />
 
   {%  endfor %}
 
   <hr />
 
   <p>Armas:</p>
   {% for arma in armas %}
       <img src="{{ arma.imagem.url }}" />
       {{ arma.nome }}
 
       {% if arma in player.armas.all %}
           <a href="vender/arma/{{ arma.pk }}">vender por {{ arma.venda }}</a>
       {% else %}
           <a href="comprar/arma/{{ arma.pk }}">comprar por {{ arma.compra }}</a>
       {% endif %}
       <br />
   {%  endfor %}
 
</div> <!-- /container -->

Isso já é meio caminho andado.
Agora só precisamos definir as urls no urls.py e escrever as funções no views.py.

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

import djangowars.views

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

urlpatterns = patterns('',
                       url(r'^$', djangowars.views.index),
                       url(r'^registrar/$', djangowars.views.registrar), # pagina de cadastro
                       url(r'^login/$', djangowars.views.logar), # pagina de login

                       url(r'^crimes/$', djangowars.views.crimes),

                       url(r'^loja/$', djangowars.views.loja), # pagina de loja
                       url(r'^loja/comprar/armadura/(\d+)/$', djangowars.views.comprar_armadura), # pagina de loja
                       url(r'^loja/vender/armadura/(\d+)/$', djangowars.views.vender_armadura), # pagina de loja
                       #url(r'^compra/arma/(\d+)/$', djangowars.views.compra_arma), # pagina de loja
                       #url(r'^venda/arma/(\d+)/$', djangowars.views.venda_arma), # pagina de loja
                       
                       # Uncomment the next line to enable the admin:
                       url(r'^admin/', include(admin.site.urls)),
)

Reparem as linhas 16~20, onde definimos todos os links referentes a loja, e os associamos as suas respectivas funções.
Como no Django os links são definidos através de Expressões Regulares, utilizamos o (d+) para informar ao Django que esperamos que seja passado um ou mais dígitos [0-1].
Essa parte montada na url será passada para a view como uma variável da chamada da função.
Fica mais fácil de compreender isso descrevendo a própria função:

#pagina de compra de armaduras
def comprar_armadura(request, item):
    if not request.user.is_authenticated(): # Se o usuario nao esta logado
        return redirect(logar)

    armadura = get_object_or_404(Armadura, pk=item) #procura a armadura no banco de dados, se nao encontrar retorna uma pagina de 404
    player = request.user.get_profile() 

   #verifica se o usuario tem dinheiro para comprar o item
    if player.carteira >= armadura.compra:
        player.carteira = player.carteira - armadura.compra #tira o valor da armadura na carteira
        #coloca a armadura na lista de armaduras que o usuario possui
        player.armaduras.add(armadura) #https://docs.djangoproject.com/en/1.4/ref/models/relations/
        player.save() #salva no banco de dados as alteracoes no usuario

    return redirect(loja)

Notem como na definição do método comprar_armadura, além da variável que já é passada por padrão (request), temos uma nova variável (item), que foi passada a partir do urls.py.
O método para vender uma armadura é análogo ao de comprar uma.
A diferença encontra-se no fato que, ao invés de subtrair o valor do item na carteira, adicionamos este valor e, ao invés de adicionar a armadura na lista de armaduras do usuários, nós a removemos.

#pagina de venda de armaduras
def vender_armadura(request, item):
    if not request.user.is_authenticated():
        return redirect(logar)

    armadura = get_object_or_404(Armadura, pk=item)
    player = request.user.get_profile()

    if armadura in player.armaduras.all():
        player.carteira = player.carteira + armadura.venda
        player.armaduras.remove(armadura) #https://docs.djangoproject.com/en/1.4/ref/models/relations/
        player.save()

    return redirect(loja)

Definimos os links, e as views, para compra e venda de armaduras.
Para comprar e vender armas é a mesma coisa.
Fica então como exercício.

4 thoughts on “Django Wars [Parte 15]: Compra e venda de itens na loja

  1. Fala rapaz, tudo certinho?

    Tow acompanhando por aqui esse jogo, acredito que tu esqueceu de colocar no urls.py a referencia pra item:

    url(r’^loja/comprar/armadura/(?P\d+)/$’, djangowars.views.comprar_armadura),

    Dessa forma, o que vier naquele espacinho da url vai ser nomeado como “item” e passado como parametro lá pra função comprar_armadura na views.py

    Pelo menos aprendi assim 😀

    1. Olá Diogo,

      Existem duas formas de montar as urls no arquivo urls.py, de acordo com a documentação do Django[1.4] (https://docs.djangoproject.com/en/1.4/topics/http/urls/)
      A forma mais simples é esta que eu utilizei, onde a expressão regular é montada mais ou menos assim url(r’^loja/comprar/armadura/(\d+)/$’, djangowars.views.comprar_armadura)
      A segunda forma é chamada de “named groups”, ou grupos nomeados, que é esta forma que você aprendeu, onde a url do exemplo que eu dei ficaria assim url(r’^loja/comprar/armadura/(?P<nome>\d+)/$’, djangowars.views.comprar_armadura).
      Este <nome> é o nome da variável que você quer dar para o parâmetro passado.

      Mas qual a diferença entre as duas formas?

      Na forma dos “named groups” é mais fácil fazer alterações no formato da URL.
      Para entender isso, vamos com um exemplo bem bacana.

      Digamos que eu tenha o método para cadastrar o aniversário de algum amigo na agenda.
      A view do cadastro possui a definição: def aniversario(ano, mes, nome)

      Na forma mais simples da URL, o URL DISPATCHER do Django coloca as variáveis com os dados na ordem em que eles aparecem na URL.
      Assim sendo, teriamos que montar uma url assim
      url(r’^aniversario/cadastrar/(\d+{4})/(\d+{2})/(\w+)/$’, views.aniversario)
      Com essa URL, o primeiro item identificado, e passado para a view é o ano, o segundo o mês e o terceiro é o nome.
      A bronca acontece se houve uma mudança de planos e agora a nossa url precisa receber primeiro o nome, depois o mês e depois o ano.
      Alterar a URL é fácil url(r’^aniversario/cadastrar/(\w+)/(\d+{2})/(\d+{4})/$’, views.aniversario)
      O problema é que agora, o primeiro item identificado é o nome, o segundo o mês e o terceiro o ano.
      Mas nossa view, def aniversario(ano, mes, nome), espera que o primeiro item recebido seja o ano, e não o nome.
      Então, além de termos que alterar a nossa URL, temos que alterar a definição da view para receber a nova ordem.
      Mas, o que acontece se mais de uma URL usa essa view?
      Acontece pau no sistema 😀

      No formato de “named groups” o URL DISPATCHER funciona diferente.
      Ao invés de mandar para a view as variáveis na ordem que elas aparecem na URL, ele manda as variáveis detectadas na URL com o nome que elas devem receber na tua view.
      Assim sendo, se temos a mesma view def aniversario(ano, mes, nome), podemos fazer a URL assim
      url(r’^aniversario/cadastrar/(?P<ano>\d+{4})/(?P<mes>\d+{2})/(?P<nome>\w+)/$’, views.aniversario)
      O URL DISPATCHER, vai encontrar a primeira variável e vai ver “Opa, essa variável tem que ter o nome ano”, e assim para cada uma.
      Se precisarmos mudar a ordem que as variáveis aparecem para nome, mes e ano, a operação é menos dolorosa, só faz-se mister alterar a URL.
      url(r’^aniversario/cadastrar/(?P<nome>\w+)/(?P<mes>\d+{2})/(?P<ano>\d+{4})/$’, views.aniversario)
      Neste caso o URL DISPATCHER vai perceber que a primeira variável tem o nome “nome”, a segunda o “mês” e a terceira o “ano”.
      Ao invés de mandar para a view na ordem que as variáveis aparecem, ele manda para a view com o nome que elas devem ser preenchidas na chamada do método.
      Se a view, já sendo bem repetitivo, tem a definição def aniversario(ano, mes, nome), o URL DISPATCHER vai fazer a chamada mais ou menos assim:
      aniversario(nome=valor1, mes=valor2, ano=valor3)
      Apesar de não ser a ordem definida, é o conjunto de nomes definidos, e assim funciona 😀
      Neste caso, dos named groups, só precisei alterar a forma de uma URL.
      Se mais de uma URL utiliza essa view, não houve impacto, pois não precisei alterar a view.

      Como no projeto do Django-Wars as views estão bem definidas, apenas uma URL por view, e eu tenho poucas views e poucas URLS, preferi utilizar o formato mais simples.
      Mas, o formato do named groups é mais seguro se o teu projeto for crescer bastante.

      Espero ter sido claro, nem um pouco confuso, e que esse texto não tenha sido muito grande 😀

Deixe um comentário

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