Aula 08 - Loja Virtual - Ecommerce - Django - List View - CBVs - FBVs

Loja Virtual - Ecommerce - Django -  Listar produtos

Agora vamos construir a list view dos produtos para o usuário comum.

CBVs (Class Based Views) versus FBVs (Function Based Views)

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

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

Listando os produtos para o usuário comum.

Abra src/products/views.py Primeiro importaremos generic views com: from django.views.generic import ListView Importaremos também o modelo produto com: from .models import Product

Iremos criar a view primeiro utilizando CBVs (Class Based Views) e depois FBVs (Function Based Views) e vê a diferença entre elas.

src/products/views.py

from django.views.generic import ListView
from django.shortcuts import render

from .models import Product

class ProductListView(ListView):
    #traz todos os produtos do banco de dados sem filtrar nada 
    queryset = Product.objects.all()

Agora vamos criar a FBVs (Function Based Views).

Obs. Não é necessário as duas formas, CBV e FBV. No código foi colocado os dois tipos apenas para ilustrar a diferença entre as duas formas de fazer uma view.

src/products/views.py

from django.views.generic import ListView
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()

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

Já criamos a view com dois tipos diferentes de implementação: CBV e FBV, agora vamos adicioná-las as nossas URLs.

Abra src/e_commerce/urls.py e insira as linhas que estão em laranja.

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
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('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)
Suba o servidor se já não estiver rodando: python manage.py runserver Acesse 127.0.0.1:8000/products/

Veja que o django tá reclamando que não existe o template html, então vamos criá-lo.

Crie então src/products/templates/products/list.html e coloque:
{{ qs }}
Observe que a FBV conhece o context, já a CBV não, então, o que fizemos anteriormente só vai funcionar para a FBV, porque ela consegue enxergar a variável de contexto {{ qs }} Faltou informar o nome do template na CBV, então, acrescente o que tá em laranja em src/products/views.py

from django.views.generic import ListView
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"

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

Já criamos a view com dois tipos diferentes de implement

Com o servidor rodando, acesse: 127.0.0.1:8000/products-fbv/ O resultado deve ser algo como: <QuerySet[<Product: Camiseta>, <Product: Tênis>]> Já no caso da CBV não vai funcionar, porque ela não conhece o context. Por isso vamos modificar a CBV. src/products/views.py

from django.views.generic import ListView
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, *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 = {
        'qs': queryset
    }
    return render(request, "products/list.html", context)
A super é um atalho para chamar a classe base, que é a generic ListView, que vai como argumento da classe filha, a que a gente criou: ProductListView. Ela recebe o nome da sub classe ProductListView como parâmetro e o self, que é a instância da própria classe. Depois a chamada do método get_context_data() para pegar o contexto, passando *args e **kargs como parâmetros. Toda CBV tem esse método, e o que esse método faz é pegar o context para qualquer query set ou qualquer coisa que a view fizer. Mas, o que é *args e **kargs? No *args e **kwargs, o asterísco ( * ) é um operador que transforma listas / dicionários em argumentos de uma função. Vamos imaginar que você queira usar a função replace em uma string. Essa função recebe 2 argumentos, o primeiro para o valor que será substituído e o segundo que é o novo valor. 'a menino'.replace('a', 'o') 'o menino'

Agora tentando passar os parâmetros em uma lista:

args = ['a','o']
'a menino'.replace(args)

Erro Lançado:

Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: replace() takes at least 2 arguments (1 given) Para que isso funcionar é só usar o operador * 'a menino'.replace(*args) Saída: 'o menino' O ** é um operador que transforma um dicionário em keyword arguments de uma função. Vamos a um exemplo, criaremos uma função que recebe dois argumentos, nome e idade:

d = {'nome' : 'Toti', 'idade': 50}
def my_two_args(nome, idade):
    print(nome, idade)

my_two_args(d)
Saída: Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: my_two_args() takes exactly 2 arguments (1 given) Corrigindo:

d = {'nome' : 'Antonio', 'idade': 50}
def my_two_args(nome, idade):
    print(nome, idade)

my_two_args(**d)
Saída: Antonio 50 Como o context pode ter vários argumentos, então podemos ter: def get_context_data('olá', 312, [item1, item2, item3], outro='olá', num=312)  Não precisamos escrever explicitamente os argumentos, basta usar *arg e **kargs. Precisamos de uma forma de pegar o context ou ver o que o context é na generic view, então acesse a generic view no browser em 127.0.0.1:8000/products/ e veja no console um dicionário onde é mostrado mais ou menos o seguinte: {'paginator': None, 'page_object': None, 'is_paginated': False, 'object_list': <QuerySet[<Product: Camiseta>, <Product: Tênis>]>, 'view': <products.views.ProductListView object at 0x01034f935a7>} Note que no browser, não aparece nada. Faça um teste, coloque no src/products/template/products/list.html o seguinte:
{{ qs}}
{{ paginator }}
{{ is_paginated }}
{{ object_list }}
Veja o resultado no browser 127.0.0.1:8000/products/ O que nos interessa é o object_list, então apague todo o resto e deixe apenas o object_list: src/products/template/products/list.html  {{ object_list }} Em src/products/views.py comente o método get_context_data e em product_list_view troque o nome qs para object_list

from django.views.generic import ListView
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, *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)
Acesse novamento o browser em 127.0.0.1:8000/products e também 127.0.0.1:8000/products-fbv/ Veja que as duas implementações estão funcionando. Vamos fazer uma modificação no src/products/template/products/list.html 
{% for obj in object_list %}

{{ obj.title }} <br/>

{% endfor%}
Veja que agora tá listando nossos produtos nas duas implementações, CBV e FBV.

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

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