Aula 44 – Loja Online – Django – Carrinho – Atualizando o Carrinho
Aula 44 – Loja Online – Django – 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.