Aula 09 – Loja Virtual – Ecommerce – Django – Detail View

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.

detalhes de cada produtos

detalhes de cada produtos

Voltar para página principal do blog

Todas as aulas desse curso

Aula 08                Aula 10

Para baixar o código como está até agora, acesse o link abaixo:
https://github.com/toticavalcanti/django_ecommerce/tree/list_view

Curta a página do Código Fluente no Facebook
https://www.facebook.com/Codigofluente-338485370069035/

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:

Digital Ocean

Esse outro link é da one.com:

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/ 🙂

Voltar para página principal do blog

Todas as aulas desse curso

Aula 08                Aula 10

Curta a página do Código Fluente no Facebook
https://www.facebook.com/Codigofluente-338485370069035/

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:

Digital Ocean

Esse outro link é da one.com:

One.com

Para baixar o código como está até agora, acesse o link abaixo:
https://github.com/toticavalcanti/django_ecommerce/tree/list_view

Obrigado, até a próxima e bons estudos. 😉

 

About The Author
-

2 Comentários

  • Rodrigo
    Reply

    Primeiro de tudo, excelente trabalho o que você tem feito aqui meu amigo! Ótima didática e conteúdo!
    Apenas para observação de todos que estiverem acompanhando por aqui, na última atualização da view de products (descomentar o get_context_data) estão faltando 2 parâmetros na chamada: *args e **kwargs, causando erro de object não esperado na função. Devereia ser assim:

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

    • toticavalcanti
      Reply

      Olá Rodrigo, blz?
      Acabei de ver no post dessa aula e também na branch detail_view no GitHub, que é a branch dessa aula e o código tá exatamente como você colocou aí, tá assim, tanto na branch detail_view como no post da aula 09:

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

      Exatamente igual ao que você colocou como o que deveria ser, com o .get_context_data(*args, **kwargs) .
      Enfim, de qualquer forma valeu. 😉

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>