Aula 44 – Loja Online – Django – Carrinho – Atualizando o Carrinho

Aula 44 – Loja Online – Django – Carrinho – Atualizando o Carrinho

Atualizando o carrinho

Atualizando o carrinho

Voltar para página principal do blog

Todas as aulas desse curso

Aula 43               Aula 45

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook

Esse é o link do código fluente no Pinterest

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

Melhore seu NETWORKING

Participe de comunidades de desenvolvedores:

Fiquem a vontade para me adicionar ao linkedin.

E também para me seguir no https://github.com/toticavalcanti.

Código final da aula:

https://github.com/toticavalcanti

Toti:

https://www.youtube.com/channel/UCUEtjLuDpcOvR3mIUr-viOA

Backing track / Play-along:

https://www.youtube.com/channel/UCT3TryVMqTqYBjf5g5WAHfA

Código Fluente

https://www.youtube.com/channel/UCgn-O-88XBAwdG9gUWkkb0w

Putz!

https://www.youtube.com/channel/UCZXop2-CECwyFYmHbhnAkAw

Aula 44 – Loja Online – Django – Carrinho – Atualizando o Carrinho

Nessa aula a gente vai atualizar o carrinho usando o front-end e não a parte de administrador do nossa loja virtual, como fizemos na aula passada.

django_ecommerce/carts/views.py


from django.shortcuts import render, redirect

from products.models import Product
from .models import Cart

def cart_home(request):
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    return render(request, "carts/home.html", {})

def cart_update(request):
    product_id = 5
    # Pega o produto com id 5
    product_obj = Product.objects.get(id=product_id)
    # Cria ou pega a instância já existente do carrinho
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    # E o produto se adiciona a instância do campo M2M 
    cart_obj.products.add(product_obj) # cart_obj.products.add(product_id)
    #cart_obj.products.remove(product_obj) # cart_obj.products.remove(product_id)
    return redirect(product_obj.get_absolute_url())

Agora vamos fazer o redirect desse produto

django_ecommerce/e_commerce/urls.py


from django.conf import settings
from django.conf.urls.static import static

from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
from carts.views import cart_home

from .views import (home_page, 
                    about_page, 
                    contact_page, 
                    login_page, 
                    logout_page,
                    register_page
)

urlpatterns = [
    path('', home_page, name='home'),
    path('about/', about_page, name='about'),
    path('contact/', contact_page, name='contact'),
    path('cart/', include("carts.urls", namespace="cart")),
    path('login/', login_page, name='login'),
    path('logout/', logout_page, name='logout'),
    path('register/', register_page, name='register'),
    path('bootstrap/', TemplateView.as_view(template_name='bootstrap/example.html')),
    path('search/', include("search.urls", namespace="search")),
    path('products/', include("products.urls", namespace="products")),
    path('admin/', admin.site.urls),
]

if settings.DEBUG:
    urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Agora crie o urls.py do carts.

django_ecommerce/carts/urls.py


from django.urls import path

app_name = "carts"

from .views import (
                        cart_home, 
                        cart_update,
                    )

urlpatterns = [
    path('', cart_home, name='home'),
    path('update/', cart_update, name='update')
]

Acesse a página de admin

http://127.0.0.1:8000/admin/

Faça o logout em seguida o login novamente e acesse:

http://127.0.0.1:8000/cart/update

Veja que ele vai redirecionar para a página do produto com o id que você passou no cart_update()

Mas, se você acessar

http://127.0.0.1:8000/cart/

Vamos modificar o views.py do carts pra usar namespace.

django_ecommerce/carts/views.py


from django.shortcuts import render, redirect

from products.models import Product
from .models import Cart

def cart_home(request):
    cart_obj = Cart.objects.new_or_get(request)
    return render(request, "carts/home.html", {})

def cart_update(request):
    product_id = 5
    # Pega o produto com id 5
    product_obj = Product.objects.get(id=product_id)
    # Cria ou pega a instância já existente do carrinho
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    # E o produto se adiciona a instância do campo M2M 
    cart_obj.products.add(product_obj) # cart_obj.products.add(product_id)
    #cart_obj.products.remove(product_obj) # cart_obj.products.remove(product_id)
    #return redirect(product_obj.get_absolute_url())
    # Vamos usar namespace cart
    return redirect("cart:home")

Acesse de novo

http://127.0.0.1:8000/cart/

Veja que o namespace funcionou.

Usar return redirect(“cart: home”) é um atalho para fazer o redirect sem ter que importar o reverse e algumas outras coisas.

É uma forma rápida de ir para url baseada no namespace(cart) e o nome da url(home).

O que precisamos fazer agora é adicionar o objeto carrinho ao contexto do view do product.

Abra o view do products e faça as alterações abaixo.

django_ecommerce/products/views.py 


from django.http import Http404

from django.views.generic import ListView, DetailView
from django.shortcuts import render, get_object_or_404

from carts.models import Cart
from .models import Product

class ProductFeaturedListView(ListView):
    template_name = "products/list.html"
    
    def get_queryset(self, *args, **kwargs):
        request = self.request
        return Product.objects.featured()

class ProductFeaturedDetailView(DetailView):
    queryset = Product.objects.all().featured()
    template_name = "products/featured-detail.html"

#Class Based View
class ProductListView(ListView):
    #traz todos os produtos do banco de dados sem filtrar nada 
    queryset = Product.objects.all()
    template_name = "products/list.html"

    # def get_context_data(self, *args, **kwargs):
    #     context = super(ProductListView, self).get_context_data(*args, **kwargs)
    #     print(context)
    #     return context

#Function Based View
def product_list_view(request):
    queryset = Product.objects.all()
    context = {
        'object_list': queryset
    }
    return render(request, "products/list.html", context)

class ProductDetailSlugView(DetailView):
    queryset = Product.objects.all()
    template_name = "products/detail.html"

    def get_context_data(self, *args, **kwargs):
        context = super(ProductDetailSlugView,  self).get_context_data(*args, **kwargs)
        cart_obj, new_obj = Cart.objects.new_or_get(self.request)
        context['cart'] = cart_obj
        return context

    def get_object(self, *args, **kwargs):
        slug = self.kwargs.get('slug')
        #instance = get_object_or_404(Product, slug = slug, active = True)
        try:
            instance = Product.objects.get(slug = slug, active = True)
        except Product.DoesNotExist:
            raise Http404("Não encontrado!")
        except Product.MultipleObjectsReturned:
            qs = Product.objects.filter(slug = slug, active = True)
            instance =  qs.first()
        return instance

#Class Based View
class ProductDetailView(DetailView):
    template_name = "products/detail.html"

    def get_context_data(self, *args, **kwargs):
        context = super(ProductDetailView, self).get_context_data(*args, **kwargs)
        print(context)
        return context

    def get_object(self, *args, **kwargs):
        pk = self.kwargs.get('pk')
        instance = Product.objects.get_by_id(pk)
        if instance is None:
            raise Http404("Esse produto não existe!")
        return instance

#Function Based View
def product_detail_view(request, pk = None, *args, **kwargs):
    instance = Product.objects.get_by_id(pk)
    print(instance)
    if instance is None:
        raise Http404("Esse produto não existe!")

    context = {
        'object': instance
    }
    return render(request, "products/detail.html", context)

Agora altere o detail.html do products

django_ecommerce/products/templates/products/detail.html


{% extends "base.html" %}

{% block content %}

  <div class='row'>
    <div class='col-12 col-md-6'>
      <h1>{{ object.title }}</h1>
      {{ object.timestamp|timesince }} atrás
      <h3>{{ "Um título qualquer"|title }}</h3>
      {{ object.description|linebreaks }} <br/>
      {% if object.image %}
        <img src='{{ object.image.url }}' class='img-fluid'/>
      {% endif %}
    </div>
    <div class='col-12 col-md-6'>
      {{ cart }}
      {% if object in cart.products.all %}
      Produto no Carrinho
      {% else %}
      Adicione ao carrinho
      {% endif %}
    </div>
  </div>

{% endblock content %}

Dê um refresh na página do produto que tá no carrinho, depois acesse a página de produtos e escolha outro que não esteja, e veja o resultado do código acima.

O produto com o id 5, no meu caso, a camiseta branca, vai imprimir no browser Produto no carrinho, enquano que os outros irão imprimir Adicione ao carrinho.

Vamos modificar novamente o products/detail.html

django_ecommerce/products/templates/products/detail.html


{% extends "base.html" %}

{% block content %}

  <div class='row'>
    <div class='col-12 col-md-6'>
      <h1>{{ object.title }}</h1>
      {{ object.timestamp|timesince }} atrás
      <h3>{{ "Um título qualquer"|title }}</h3>
      {{ object.description|linebreaks }} <br/>
      {% if object.image %}
        <img src='{{ object.image.url }}' class='img-fluid'/>
      {% endif %}
    </div>
    <div class='col-12 col-md-6'>
      {{ cart }}
      {% if object in cart.products.all %}
      Produto no carrinho<button class='btn btn-link'>Excluir</button>
      {% else %}
      <button class='btn btn-success'>Adicionar ao carrinho</button>
      {% endif %}
    </div>
  </div>

{% endblock content %}

Agora vamos refatorar o views.py do carts para fazer o excluir e o adicionar funcionar.

django_ecommerce/carts/views.py


from django.shortcuts import render, redirect

from products.models import Product
from .models import Cart

def cart_home(request):
    cart_obj = Cart.objects.new_or_get(request)
    return render(request, "carts/home.html", {})

def cart_update(request):
    product_id = 5
    # Pega o produto com id 5
    product_obj = Product.objects.get(id=product_id)
    # Cria ou pega a instância já existente do carrinho
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    if product_obj in cart_obj.products.all():
        cart_obj.products.remove(product_obj) # cart_obj.products.remove(product_id)
    else:
        # E o produto se adiciona a instância do campo M2M 
        cart_obj.products.add(product_obj) # cart_obj.products.add(product_id)
    
    # retorna redirect(product_obj.get_absolute_url())
    return redirect("cart:home"))

Acesse de novo

http://127.0.0.1:8000/cart/update

Em seguida acesse

http://127.0.0.1:8000/admin/carts/cart/28/

Veja que ficou só o valor da “taxa”, o 10.00.

Se não tem nenhum produto o carrinho deveria tá zerado e não com 10.00 no Total

Vamos ajustar isso no models.py do carts.

django_ecommerce/carts/models.py


from django.conf import settings
from django.db import models

from django.db.models.signals import pre_save, post_save, m2m_changed

from products.models import Product


User = settings.AUTH_USER_MODEL

class CartManager(models.Manager):
    def new_or_get(self, request):
        cart_id = request.session.get("cart_id", None)
        qs = self.get_queryset().filter(id=cart_id)
        if qs.count() == 1:
            new_obj = False
            cart_obj = qs.first()
            if request.user.is_authenticated and cart_obj.user is None:
                cart_obj.user = request.user
                cart_obj.save()
        else:
            cart_obj = Cart.objects.new(user=request.user)
            new_obj = True
            request.session['cart_id'] = cart_obj.id
        return cart_obj, new_obj

    def new(self, user=None):
        user_obj = None
        if user is not None:
            if user.is_authenticated:
                user_obj = user
        return self.model.objects.create(user=user_obj)

class Cart(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null = True, blank = True)
    products = models.ManyToManyField(Product,  blank = True)
    subtotal = models.DecimalField(default = 0.00, max_digits=100, decimal_places = 2)
    total = models.DecimalField(default = 0.00, max_digits=100, decimal_places = 2)
    updated = models.DateTimeField(auto_now = True)
    timestamp = models.DateTimeField(auto_now_add = True)

    objects = CartManager()

    def __str__(self):
        return str(self.id)

def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
  if action == 'post_add' or action == 'post_remove' or action == 'post_clear':
    products = instance.products.all() 
    total = 0 
    for product in products: 
      total += product.price 
    if instance.subtotal != total:
      instance.subtotal = total
      instance.save()

m2m_changed.connect(m2m_changed_cart_receiver, sender = Cart.products.through)

def pre_save_cart_receiver(sender, instance, *args, **kwargs):
    
def pre_save_cart_receiver(sender, instance, *args, **kwargs):
    if instance.subtotal > 0:
        instance.total = instance.subtotal  + 10 # considere o 10 como uma taxa de entrega
    else:
        instance.total = 0.00

pre_save.connect(pre_save_cart_receiver, sender = Cart)

Faça o mesmo teste anterior e veja que quando a gente acessa a url:

http://127.0.0.1:8000/cart/update

Pela segunda vez, como já tem o produto que a gente tá colocando em hard code, que é o de id 5 no meu caso, ele remove por causa do if product_obj in cart_obj.products.all(): no views do carts.

E agora ele zera certinho o carrinho por causa do ajuste do código acima em azul, no models do cart.

Por essa aula é só, nos vemos na próxima. 🙂

Voltar para página principal do blog

Todas as aulas desse curso

Aula 43               Aula 45

Código final da aula:

https://github.com/toticavalcanti

Outros canais

Toti:

https://www.youtube.com/channel/UCUEtjLuDpcOvR3mIUr-viOA

Backing track / Play-along:

https://www.youtube.com/channel/UCT3TryVMqTqYBjf5g5WAHfA

Código Fluente

https://www.youtube.com/channel/UCgn-O-88XBAwdG9gUWkkb0w

Putz!

https://www.youtube.com/channel/UCZXop2-CECwyFYmHbhnAkAw

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no
Facebook

Esse é o link do código fluente no Pinterest

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

É isso, ficamos por aqui \o/ e até a próxima 😉

About The Author
-

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>