Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django queryset - searching for firstname and lastname

i have a django app that retrieve all subjects from a single table of users. i've also implemented an input search form, this is the query performed:

all_soggs =     Entity.objects.filter(lastname__istartswith=request.GET['query_term']).order_by('lastname')
if(all_soggs.count()==0):
    all_soggs = Entity.objects.filter(firstname__istartswith=request.GET['query_term']).order_by('firstname')

as you can see the query first search for matching items by lastname, and then by firstname. this works until i insert the complete name 'firstaname lastname' or 'lastname firstname', in this case there's no results. how can i modify the query to make a better search?

thanks - luke

like image 237
Luke Avatar asked Jan 25 '12 20:01

Luke


People also ask

Can I filter a QuerySet Django?

With the Django QuerySet class, you can apply filters that return QuerySets defined by your filters. The filter() method returns all objects that match the keyword arguments given to the method.

What is difference between contains and Icontains in Django?

Definition and Usage The contains lookup is used to get records that contains a specified value. The contains lookup is case sensitive. For a case insensitive search, use the icontains lookup.

What does .values do in Django?

values() Returns a QuerySet that returns dictionaries, rather than model instances, when used as an iterable. Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects.


2 Answers

Copy/paste from: https://stackoverflow.com/a/17361729/1297812

from django.db.models import Q 

def find_user_by_name(query_name):
   qs = User.objects.all()
   for term in query_name.split():
     qs = qs.filter( Q(first_name__icontains = term) | Q(last_name__icontains = term))
   return qs
like image 171
laffuste Avatar answered Oct 16 '22 16:10

laffuste


You need Q objects and you also need to split your query into separate terms (since no first name will match the full string "Firstname Lastname").

Here's an idea to match any first or last name starting with either "Firstname" or "Lastname" in the search "Firstname Lastname".

This is a generic search - adjust the query to suit your specific needs!

Edit: oops, I really don't like using reduce since it looks confusing, but these need to be ORed together and we can't do a more verbose version because the number of terms is unknown.

import operator
from django.db.models import Q

search_args = []
for term in request.GET['query_term'].split():
    for query in ('first_name__istartswith', 'last_name__istartswith'):
        search_args.append(Q(**{query: term}))

all_soggs = Entity.objects.filter(reduce(operator.or_, search_args))

To clarify how to use Q objects, given the search "Firstname Lastname" the previous query is equal to:

Entity.objects.filter(
    Q(first_name__istartswith="Firstname") | Q(last_name__istartswith="Firstname") |
    Q(first_name__istartswith="Lastname") | Q(last_name__istartswith="Lastname")
    )
like image 21
Yuji 'Tomita' Tomita Avatar answered Oct 16 '22 14:10

Yuji 'Tomita' Tomita