Complete Search App - lhmisho/django-eCommerce GitHub Wiki
create a search app at the same lebel of your project (myproj/search)
....myproj . ....seaarch
django-admin startapp search
myproj/settings.py
INSTALLED_APPS = [
...............
'search',
...............
]
search/view.py
from django.shortcuts import render
from django.views.generic import ListView
from products.models import Product
# Create your views here.
class SearchProductView(ListView):
# first way to manage list view
#queryset = Product.objects.all()
template_name = 'search/view.html'
# passing request.GET.q as a query to the template
def get_context_data(self, *args, **kwargs):
request = self.request
context = super(SearchProductView, self).get_context_data(*args, **kwargs)
query = request.GET.get('q')
context['query'] = query
return context
def get_queryset(self, *args, **kwargs):
request = self.request
query = request.GET.get('q',None)
print(query)
if query is not None:
return Product.objects.search(query) # using custom query from products.models
return Product.objects.featured()
Now i am going to create tag for better search result which means i can add some tag on my product for better result Now create a tags app at the same level of search and products app...
django-admin startapp search
Than registering the tags app on my projects settings.py
INSTALLED_APPS = [
...............
'search',
'tags',
...............
]
Now i am going to create tag model --- tags/model.py
from django.db import models
from django.urls import reverse
from products.utils import unique_slug_generator
from django.db.models.signals import pre_save, post_save
from products.models import Product
# Create your models here.
class Tag(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField()
timestamp = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
products = models.ManyToManyField(Product, blank=True)
def __str__(self):
return self.title
def tag_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(tag_pre_save_receiver, sender=Tag)
Products.utils.py code .....
# link for slug generator:- https://www.codingforentrepreneurs.com/blog/a-unique-slug-generator-for-django/
# link for random string generator:- https://www.codingforentrepreneurs.com/blog/random-string-generator-in-python/
import random
import string
from django.utils.text import slugify
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
# creating unique order id for order apps
def unique_order_id_generator(instance, new_slug=None):
"""
This is for django project with an order_id field
"""
new_order_id = random_string_generator().upper() # key : 1DSWA3FG somthing like that
Klass = instance.__class__
qs_exists = Klass.objects.filter(order_id=new_order_id).exists()
if qs_exists:
return unique_slug_generator(instance)
return new_order_id
def unique_slug_generator(instance, new_slug=None):
"""
This is for django project with and it's assume that your
instance has a model with a slug field and title character (char) field
"""
if new_slug is not None:
slug = new_slug
else:
slug = slugify(instance.title)
Klass = instance.__class__
qs_exists = Klass.objects.filter(slug=slug).exists()
if qs_exists:
new_slug = "{slug}-{randstr}".format(
slug=slug,
randstr=random_string_generator(size=4)
)
return unique_slug_generator(instance, new_slug=new_slug)
return slug
Now it's time to create custom query and model manager for better handle products/models.py
import os
import random
from django.db.models import Q # importing for search look-up
from django.db import models
from django.urls import reverse
from .utils import unique_slug_generator
from django.db.models.signals import pre_save, post_save
# creating my own custom queryset
class ProductQueryset(models.query.QuerySet):
# this is for active products query
def active(self):
return self.filter(active=True)
# this custom query is for featured products
def featured(self):
return self.filter(featured=True, active=True)
# this is for search fields qery
def search(self, query):
lookups = (Q(title__icontains = query) |
Q(description__icontains = query) |
Q(price__icontains = query) |
Q(tag__title__icontains = query))
return self.filter(lookups).distinct()
# creating my own 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__icontains = query) | Q(description__icontains = query) | Q(price__icontains = query) | Q(tag__title__icontains = query)
return self.filter(lookups).distinct()
# model manager for custom queryset
class ProductManager(models.Manager):
def get_queryset(self):
return ProductQueryset(self.model, using=self._db)
# all is extend by active
# if we do active false than all false item will not apear in all() method
def all(self):
return self.get_queryset().active()
# custom query method for featured items
def featured(self):
query = self.get_queryset().featured()
return query
# model manager for getiing data as get_by_id()
def get_by_id(self, pk):
#return self.get_queryset().filter(id=pk) # i can use id as id or pk
qs = self.get_queryset().filter(id=pk)
if qs.count() == 1:
return qs.first()
return None
# taking qury arg from search.views and sending it to customqury model
def search(self,query):
return self.get_queryset().active().search(query)
class Product(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField()
######################################
### and so on fields #################
######################################
objects = ProductManager()
def get_absolute_url(self):
# first way
#return f"/products/{self.slug}/"
# most effictive way
return reverse('products:detail',kwargs={'slug':self.slug})
def __str__(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)
>> python manage.py shell
#### for Tag Apps
>>> from tags.models import Tag
>>> Tag.objects.all()
<QuerySet [<Tag: my car>, <Tag: black cycle>]>>>> Tag.objects.last()
<Tag: black cycle>
>>> black = Tag.objects.all()
>>> black.titleTraceback (most recent call last):
File "<console>", line 1, in <module>AttributeError: 'QuerySet' object has no attribute 'title'
>>> opt = Tag.objects.all()>>> opt.title
Traceback (most recent call last):
File "<console>", line 1, in <module>AttributeError: 'QuerySet' object has no attribute 'title'
>>> opt = Tag.objects.first()>>> opt
<Tag: my car>
>>> opt = Tag.objects.last()
>>> opt
<Tag: black cycle>
>>> black = Tag.objects.last()
>>> black
<Tag: black cycle>
>>> bleack.title
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'bleack' is not defined
>>> black = Tag.objects.all()
>>> black
<QuerySet [<Tag: my car>, <Tag: black cycle>]>
>>> Tag.objects.last()
<Tag: black cycle>
>>> black = Tag.objects.last()
>>> black
<Tag: black cycle>
>>> black.slug
'black-cycle'
>>> black.title
'black cycle'
>>> black.products
<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x7f49499a9518>
>>> black.products.all()
<ProductQueryset [<Product: car>, <Product: cycle>, <Product: cycle>]>
>>> product = black.products.all()
>>> products
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'products' is not defined
>>> product
<ProductQueryset [<Product: car>, <Product: cycle>, <Product: cycle>]>
>>> products.title
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'products' is not defined
>>> products
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'products' is not defined
>>> product.title
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'ProductQueryset' object has no attribute 'title'
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>> exit(
... )
######Experiment for Product apps
(eCommerce)lhmisho@lhmisho:~/myPythonProjects/eCommerce/eshop$python manage.py shell
Python 3.6.6 (default, Sep 12 2018, 18:26:19)
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] onlinux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from products.models import Product
>>> Product.objects.all()
<ProductQueryset [<Product: car>, <Product: truck>, <Product: but>, <Product: rikshaw>, <Product: cycle>, <Product: cycle>, <Product: shirt>]>
>>> shirt = Product.objects.first()
>>> shirt.title
'car'
>>> shirt.slug
'car-qj22'
>>> shirt.tags
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Product' object has no attribute 'tags'
>>> shirt.tag_set.all()
<Query>