Aula 35 – Loja Online – Django – Melhorando o search com Q Lookups
Aula 35 – Loja Online – Django – Melhorando o search com Q Lookups
Voltar para página principal do blog
Todas as aulas desse curso
Aula 34 Aula 36
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 GITHUB.
Ah, se puder, clica na estrela nos meus repositórios pra dá uma força ao meu perfil no GITHUB
Código final da aula:
https://github.com/toticavalcanti/django_ecommerce/tree/q_lookups
Recapitulando
Na aula passada criamos um formulário de pesquisa isolado para poder reutilizar o código.
Usamos o método de GET passando a URL, nesse caso o /search, a ser tratada pela src/search/view.py.
Melhorando o search com Q Lookups
Nossa busca só funciona pelo título, não pesquisa por outros campos.
Vamos utilizar Q que iremos importar do django.db.models, ele nos ajudará a compor querysets.
Vamos ao código.
src/search/views.py
from django.db.models import Q
from django.shortcuts import render
from django.views.generic import ListView
from products.models import Product
class SearchProductView(ListView):
template_name = "search/view.html"
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
query = self.request.GET.get('q')
context['query'] = query
#SearchQuery.objects.create(query=query)
return context
def get_queryset(self, *args, **kargs):
request = self.request
print('Solicitação', request)
result = request.GET
print('Resultado: ', result)
query = result.get('q', None) # method['q']
print('Consulta', query)
if query is not None:
lookups = Q(title__contains = query) | Q(description__contains = query)
return Product.objects.filter(lookups).distinct()
return Product.objects.featured()
O distinct é para não repetir um mesmo produto, já que um mesmo produto pode se encaixar nas duas queries.
Refatorando
Vamos transferir essa responsabilidade de devolver os itens correspondentes a pesquisa do usuário, para o modelo.
Vamos mover o conteúdo em azul no código acima para o src/products/models.py.
src/products/models.py
from django.db.models import Q
from django.db import models
from .utils import unique_slug_generator
from django.db.models.signals import pre_save
from django.urls import reverse
#Custom queryset
class ProductQuerySet(models.query.QuerySet):
def active(self):
return self.filter(active = True)
def featured(self):
return self.filter(featured = True, active = True)
def search(self, query):
lookups = Q(title__contains = query) | Q(description__contains = query)
return self.filter(lookups).distinct()
class ProductManager(models.Manager):
def get_queryset(self):
return ProductQuerySet(self.model, using = self._db)
def all(self):
return self.get_queryset().active()
def featured(self):
#self.get_queryset().filter(featured = True)
return self.get_queryset().featured()
def get_by_id(self, id):
qs = self.get_queryset().filter(id = id)
if qs.count() == 1:
return qs.first()
return None
def search(self, query):
return self.get_queryset().active().search(query)
# Create your models here.
class Product(models.Model): #product_category
title = models.CharField(max_length=120)
slug = models.SlugField(blank = True, unique = True)
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=20, default=100.00)
image = models.FileField(upload_to = 'products/', null = True, blank = True)
featured = models.BooleanField(default = False)
active = models.BooleanField(default = True)
timestamp = models.DateTimeField(auto_now_add = True)
objects = ProductManager()
def get_absolute_url(self):
#return "/products/{slug}/".format(slug = self.slug)
return reverse("products:detail", kwargs={"slug": self.slug})
#python 3
def __str__(self):
return self.title
#python 2
def __unicode__(self):
return self.title
def product_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(product_pre_save_receiver, sender = Product)
src/search/views.py
from django.shortcuts import render
from django.views.generic import ListView
from products.models import Product
class SearchProductView(ListView):
template_name = "search/view.html"
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
query = self.request.GET.get('q')
context['query'] = query
#SearchQuery.objects.create(query=query)
return context
def get_queryset(self, *args, **kargs):
request = self.request
print('Solicitação', request)
result = request.GET
print('Resultado: ', result)
query = result.get('q', None) # method['q']
print('Consulta', query)
if query is not None:
return Product.objects.search(query)
return Product.objects.featured()
Vamos acrescentar o preço também.
src/products/models.py
from django.db.models import Q
from django.db import models
from .utils import unique_slug_generator
from django.db.models.signals import pre_save
from django.urls import reverse
#Custom queryset
class ProductQuerySet(models.query.QuerySet):
def active(self):
return self.filter(active = True)
def featured(self):
return self.filter(featured = True, active = True)
def search(self, query):
lookups = (Q(title__contains = query) |
Q(description__contains = query) |
Q(price__contains = query))
return self.filter(lookups).distinct()
class ProductManager(models.Manager):
def get_queryset(self):
return ProductQuerySet(self.model, using = self._db)
def all(self):
return self.get_queryset().active()
def featured(self):
#self.get_queryset().filter(featured = True)
return self.get_queryset().featured()
def get_by_id(self, id):
qs = self.get_queryset().filter(id = id)
if qs.count() == 1:
return qs.first()
return None
def search(self, query):
return self.get_queryset().active().search(query)
# Create your models here.
class Product(models.Model): #product_category
title = models.CharField(max_length=120)
slug = models.SlugField(blank = True, unique = True)
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=20, default=100.00)
image = models.FileField(upload_to = 'products/', null = True, blank = True)
featured = models.BooleanField(default = False)
active = models.BooleanField(default = True)
timestamp = models.DateTimeField(auto_now_add = True)
objects = ProductManager()
def get_absolute_url(self):
#return "/products/{slug}/".format(slug = self.slug)
return reverse("products:detail", kwargs={"slug": self.slug})
#python 3
def __str__(self):
return self.title
#python 2
def __unicode__(self):
return self.title
def product_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(product_pre_save_receiver, sender = Product)