Whats wrong with my search string? I am not getting proper data - django

I want to implement search on my django project. On my following queryset, with else condition its passing correct data. But with if condition whatever I search, it shows nothing.
def get_queryset(self):
category = self.request.GET['category']
query = self.request.GET['q']
if category == 'all':
products = Products.objects.filter(Q(name__icontains=query) | Q(category__name__icontains=query)).all()
else:
products = Products.objects.filter(Q(category__slug=category), Q(category__slug__icontains=self.request.GET['q']) | Q(name__icontains=self.request.GET['q']))

Related

How to make search more accurate in Django?

so on the way of learning process, I am making my first side-project on django.
I want to make my search more accurate, for example: when post body contains text with 3 words "I love stackoverflow" and someone searches for "I stackoverflow" (without word LOVE), result is not shown on the search page.
What could be the best approach in this case to get the result, even if the post body does not contain words in that order as a search query?
views.py
def search(request):
posts = Post.objects.all().order_by('title')
query = request.GET.get('q')
print(query)
if query:
posts = Post.objects.filter(
Q(title__icontains=query)|
Q(body__icontains=query)
)
context = {
"posts": posts,
}
return render(request, "search.html", context)
I'd recommend using full text search with django haystack with any search engine. But, to respond to your case, something like following would do the trick, though is not very optimised:
from django.db.models import Q
# consider only words which are having a length greater than 2
# also, words should be sanitised and cleaned before using for db queries.
# use a form for that.
parts = [i for i in request.GET.get('q').split(' ') if len(i) >= 3]
qs = Q()
query = [qs | Q(title__icontains=query) | Q(body__icontains=query) for q in parts]
result = Post.objects.filter(query).order_by().distinct()
Django provides multiple efficient ways to search on a postgreSQL database that you can find on the official docs.
Try to split your query
from itertools import chain
def search(request):
posts = Post.objects.all().order_by('title')
query = request.GET.get('q')
if query:
words = query.split(" ")
results = []
for word in words:
match = posts.filter(
Q(title__icontains=word)|
Q(body__icontains=word)
)
if match:
results.append(match)
posts = set(chain(*results))
context = {
"posts": posts,
}
return render(request, "search.html", context)

Dynamic search using date

Can any one please help me i want to search my expenses income which is in my models.py using date wise dynamic search where user will input date and he will see the result in template i dont know how to code that template ..I tried form but not working.. :(
my views.py
def date_page(request):
f_date = '2018-12-05'
t_date = '2019-09-12'
from_date = datetime.datetime.strptime(f_date, "%Y-%m-%d").date()
to_date = datetime.datetime.strptime(t_date, "%Y-%m-%d").date()
date_queryset = Add.objects.filter(date__range=(from_date, to_date))
print (date_queryset)
return render (request , 'date_page.html',)
Pass the date value as URL parameter and fetch it using request.GET as,
def date_page(request):
f_date = request.GET.get("f_date")
t_date = request.GET.get("t_date")
date_queryset = Add.objects.filter(date__range=(f_date, t_date))
print(date_queryset)
return render(request, 'date_page.html', )
Example URL : /api/end-point/expenses/?f_date=2018-12-05&t_date=2019-09-12

Django request.GET. Search. Different results, depending on the value

There is a search form. It has a drop-down list. Each item in this list has different meanings. After clicking, a search is performed, ulr looks as follows:
http://127.0.0.1:8000/search?wantbuy=kv
http://127.0.0.1:8000/search?wantbuy=ls
http://127.0.0.1:8000/search?wantbuy=km
my views.py:
kv = kv.objects.all()
ls = ls.objects.all()
km = km.objects.all()
if 'wantbuy' in request.GET:
wantbuy = request.GET['wantbuy']
if wantbuy:
queryset_list = km
Now, it doesn’t matter what value it 'wantbuy', I get all the objects from 'km'.
Tell me how to do it better? As for each url value, display your objects? I want to:
http://127.0.0.1:8000/search?wantbuy=kv
Shows all objects
kv = kv.objects.all()
etc.
Thank!
You can have several conditions to set the variable depending on the parameter
wantbuy = request.GET.get('wantbuy')
if wantbuy == 'kv':
queryset_list = kv.object.all()
elif wantbuy == 'ls':
queryset_list = ls.object.all()
elif wantbuy == 'km':
queryset_list = km.object.all()
else:
# Raise a 404 or do something else

Change query parameter via select

I have a model Dish and a model Menu:
class MenuItem(models.Model):
dish_name=models.TextField(unique=False)
price=models.DecimalField(max_digits=5,decimal_places=2,blank=True)
main_ngredient=models.TextField(unique=False)
course=models.CharField(max_length=100)
menu=models.ForeignKey('Menu')
def __unicode__(self):
return name
class Menu(models.Model):
restaurant=models.TextField(unique=False)
year=models.IntegerField(unique=False)
location=models.TextField(unique=False)
status=models.CharField(unique=False,max_length=20)
NYPLid=models.IntegerField(unique=True)
def __unicode__(self):
return restaurant
def __period__(self):#adapted from http://stackoverflow.com/questions/2272149/round-to-5or-other-number-in-python
p=int(10*round(float(self.year)/10))
if p < self.year:
return "%s-%s"%(p,p+5)
else:
return "%s-%s"%(p-5,p)
period=property(__period__)
I have a view Search:
def search(request):
errors = []
form = SearchForm(request.GET)
if form.is_valid():
cd = form.cleaned_data
row = cd['row']
query = cd['query']
dish_row_dict = {"dish_name":'name__icontains=query',
"main_ingredient":"ingredient__icontains=query",
"course":"course__iexact=query"
}
menu_row_dict = {"year":'year__exact=query',
"period":'period__exact=query',
"location":'location__icontains=query',
"restaurant":"restaurant__icontains=query",
}
if row in dish_row_dict:
dishes = MenuItem.objects.filter(eval(dish_row_dict[row]))
elif row in menu_row_dict:
dishes = MenuItem.objects.filter(eval("menu__%s"%(menu_row_dict[row])))
return render_to_response("search_returns.html",{"dishes":dishes})
return render_to_response("search_page.html",{"form":form})
I have a form SearchForm:
class SearchForm(forms.Form):
row = forms.ChoiceField([("dish_name","Dish Name"),("year","Year"),
("period","Five-Year Period"),("location","Location"),
("main_ingredient","Main Ingredient"),("course","Course or Dish Type"),("restaurant","Restaurant"),])
query = forms.CharField())
I'd like users to be able to choose one of the select options, and then do a query based on their choice (e.g., search by dish name if they select "Dish Name".) They way I'm doing things now, with a dictionary+eval() isn't working (I know, I know, eval = bad, but I wasn't sure how else to do it!)
I feel like this isn't an exotic or uncommon thing, but I'll be damned if I can find anything about it online. I suspect the answer has something to do with MultiValueField or something like that, but I really don't understand how to make that work.
Any help would be greatly appreciated.
You can forget the =query and the eval() part and simply build a dict, and pass it as kwargs:
filter_keys = {
# menuitem queries
"dish_name":'name__icontains',
"main_ingredient": "ingredient__icontains",
"course": "course__iexact",
# menu queries
"year": 'menu__year__exact',
"period": 'menu__period__exact',
"location": 'menu__location__icontains',
"restaurant": "menu__restaurant__icontains",
}
...
if row in filter_keys:
dishes = MenuItem.objects.filter(**{filter_keys[row]: query})
The ** is a Python way of passing named parameters as a dict.

Searching for Records

I've come up with a simple search view to search for records in my app. The user just enters all parameters in the search box then all this is matched against the database, then results are returned. One of these fields is the phone number....now in the database it's stored in the format XXX-XXX-XXX. A search, for example, for "765-4321" pull up only "416-765-4321...however I want it to return both "416-765-4321" and "4167654321"
My view is as below:
def search(request, page_by=None):
query = request.GET.get('q', '')
if query:
term_list = query.split(' ')
q = Q(first_name__icontains=term_list[0]) |
Q(last_name__icontains=term_list[0]) |
Q(email_address__icontains=term_list[0]) |
Q(phone_number__icontains=term_list[0])
for term in term_list[1:]:
q.add((Q(first_name__icontains=term) |
Q(last_name__icontains=term) |
Q(email_address__icontains=term) |
Q(phone_number__icontains=term)), q.connector)
results = Customer.objects.filter(q).distinct()
all = results.count()
else:
results = []
if 'page_by' in request.GET:
page_by = int(request.REQUEST['page_by'])
else:
page_by = 50
return render_to_response('customers/customers-all.html',
locals(), context_instance=RequestContext(request))
One option is to save stripped-down number in separate field and search by it