Aula 09 - Loja Virtual - Ecommerce - Django - Detail View
Loja Virtual - Ecommerce - Django - Detalhes de cada produto
Agora vamos construir a página que vai mostrar os detalhes de cada produtos para o usuário comum.
Vou deixar meu link de referidos na digitalocean pra vocês.
Quem se cadastrar por esse link, ganha $100.00 dólares de crédito na digitalocean:
Esse outro link é da one.com:
Detail View
Será bem parecido com o list view que fizemos na aula passada. Vamos implementar as duas versões da detail view, como fizemos na product list view: Class Based View e Function Based View.
Não é necessário ter as duas versões, CBV e FBV, nesse tutorial estamos fazendo as duas versões apenas para mostrar a diferença entre as implementações.
Em
src/products/views.py crie a CBV e FBV da detail view. O que tá em laranja é o que tá sendo alterado.
from django.views.generic import ListView, DetailView
from django.shortcuts import render
from .models import Product
#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):
#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 Based View
class ProductDetailView(DetailView):
#traz todos os produtos do banco de dados sem filtrar nada
queryset = Product.objects.all()
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
#Function Based View
def product_detail_view(request):
queryset = Product.objects.all()
context = {
'object_list': queryset
}
return render(request, "products/detail.html", context)
Agora em
src/e_commerce/urls.py importe a CBV e a FBV da detail view e adicione ao urlpatterns:
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
from products.views import ProductListView, product_list_view, ProductDetailView, product_detail_view
from .views import home_page, about_page, contact_page, login_page, register_page
urlpatterns = [
path('', home_page),
path('about/', about_page),
path('contact/', contact_page),
path('login/', login_page),
path('register/', register_page),
path('products/', ProductListView.as_view()),
path('products-fbv/', product_list_view),
path('products/<int:pk>', ProductDetailView.as_view()),
path('products-fbv/<int:pk>', product_detail_view),
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)
Vamos dá uma olhada em como uma query funciona.
Com o servidor rodando acesse:
127.0.0.1:8000/products-fbv/2
Com esse request, tentamos acessar o produto com o id 2, através da Function Based View da detail view, isto é, os detalhes do produto com id 2.
Isso irá lançar uma mensagem de erro no browser, mais ou menos assim:
product_detail_view() got an unexpected keyword argument 'pk'
Vamos colocar o *args e o **kwargs na
product_detail_view e imprimir no console para ver o conteúdo que eles trazem.
src/products/views.py
from django.views.generic import ListView, DetailView
from django.shortcuts import render
from .models import Product
#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):
#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 Based View
class ProductDetailView(DetailView):
#traz todos os produtos do banco de dados sem filtrar nada
queryset = Product.objects.all()
template_name = "products/detail.html"
#def get_context_data(self):
#context = super(ProductDetailView, self).get_context_data(*args, **kwargs)
#print(context)
#return context
#Function Based View
def product_detail_view(request, *args, **kwargs):
print(args)
print(kwargs)
queryset = Product.objects.all()
context = {
'object_list': queryset
}
return render(request, "products/detail.html", context)
Note que o erro já era, porque agora
product_detail_view tá recebendo *kargs e **kwargs.
O resultado do print no console será algo como: () do args e {'pk': '2'} do kwargs.
Vamos adicionar pk = None nos argumentos da
product_detail_view.
src/products/views.py
from django.views.generic import ListView, DetailView
from django.shortcuts import render
from .models import Product
#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):
#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 Based View
class ProductDetailView(DetailView):
#traz todos os produtos do banco de dados sem filtrar nada
queryset = Product.objects.all()
template_name = "products/detail.html"
#def get_context_data(self):
#context = super(ProductDetailView, self).get_context_data(*args, **kwargs)
#print(context)
#return context
#Function Based View
def product_detail_view(request, pk = None, *args, **kwargs):
print(args)
print(kwargs)
queryset = Product.objects.all()
context = {
'object_list': queryset
}
return render(request, "products/detail.html", context)
Veja que o resultado do print args e kwargs agora estão vazios.
Cada objeto django por padrão tem uma chave primária, é o id do objeto.
Ela é criada automaticamente.
Sempre que criamos um objeto no django, ele cria um identificador para o objeto.
Vamos pegar o id do object com
Product.objects.get().
src/products/views.py
from django.views.generic import ListView, DetailView
from django.shortcuts import render
from .models import Product
#Class Based View
class ProductListView(ListView):
#traz todos os produtos do banco de dados sem filtrar nada
queryset = Product.objects.all()
template_name = "products/detail.html"
#def get_context_data(self):
#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 Based View
class ProductDetailView(DetailView):
#traz todos os produtos do banco de dados sem filtrar nada
queryset = Product.objects.all()
template_name = "products/detail.html"
#def get_context_data(self):
#context = super(ProductDetailView, self).get_context_data(*args, **kwargs)
#print(context)
#return context
#Function Based View
def product_detail_view(request, pk = None, *args, **kwargs):
instance = Product.objects.get(pk = pk) #get the object id
context = {
'object': instance
}
return render(request, "products/detail.html", context)
Com o servidor rodando acesse:
127.0.0.1:8000/products-fbv/4
Será lançada uma exceção dizendo:
product matching query does not exists (produto correspondente a consulta não existe)
Simplesmente porque esse object com id 4 não existe no banco.
Teste agora a CBV:
127.0.0.1:8000/products/4
No product found matching the query (Nenhum produto encontrado correspondente à consulta)
Uma maneira de lidar com isso é usar o
get_object_or_404, para isso vamos modificar o
src/products/views.py
from django.views.generic import ListView, DetailView
from django.shortcuts import render, get_object_or_404
from .models import Product
#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):
#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 Based View
class ProductDetailView(DetailView):
#traz todos os produtos do banco de dados sem filtrar nada
queryset = Product.objects.all()
template_name = "products/detail.html"
#def get_context_data(self):
#context = super(ProductDetailView, self).get_context_data(*args, **kwargs)
#print(context)
#return context
#Function Based View
def product_detail_view(request, pk = None, *args, **kwargs):
#instance = Product.objects.get(pk = pk) #get the object id
instance = get_object_or_404(Product, pk = pk)
context = {
'object': instance
}
return render(request, "products/detail.html", context)
Com o servidor rodando acesse:
127.0.0.1:8000/products-fbv/4
Veja que a FBV agora não lança nenhuma exceção e sim o mesmo erro que a CBV.
No product found matching the query (Nenhum produto encontrado correspondente à consulta)
Agora vamos descomentar o método
get_context_data na nossa classe
ProductDetailView em
src/products/views.py
from django.views.generic import ListView, DetailView
from django.shortcuts import render, get_object_or_404
from .models import Product
#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):
#context = super(ProductDetailView, 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 Based View
class ProductDetailView(DetailView):
#traz todos os produtos do banco de dados sem filtrar nada
queryset = Product.objects.all()
template_name = "products/detail.html"
def get_context_data(self):
context = super(ProductDetailView, self).get_context_data(*args, **kwargs)
print(context)
return context
#Function Based View
def product_detail_view(request, pk = None, *args, **kwargs):
#instance = Product.objects.get(pk = pk) #get the object id
instance = get_object_or_404(Product, pk = pk)
context = {
'object': instance
}
return render(request, "products/detail.html", context)
Acesse um produto que exista.
O produto com id 2 por exemplo, existe, no meu caso é o tênis:
127.0.0.1:8000/products/2
Agora o browser irá mostrar: TemplateDoesNotExist at /products/2/, se você olhar no console, verá o resultado do print do contexto, algo como:
{'object': <Product: Tênis>, 'product': <Product: Tênis>, 'view': <products.views.ProductDetailView object at ....}
Vamos criar o template da detail view.
src/products/template/products/detail.html
{{ object.title }} <br/>
{{ object.description }} <br/>
Veja o resultado no browser
127.0.0.1:8000/products/2
Valeu, até. \o/ :)
Vou deixar meu link de referidos na digitalocean pra vocês.
Quem se cadastrar por esse link, ganha $100.00 dólares de crédito na digitalocean:
Esse outro link é da one.com:
Obrigado, até a próxima e bons estudos. ;)