Reputation: 2913
I'm aware of full text search applications like Django Solr and solango, etc.
What I'm looking to built is more akin to an advanced search for a real estate site. E.g they can choose location, price, etc. similar to www.viewr.com advanced search.
What I have done so far is this, under the models custom manager:
def advanced_search(self, district, location, type, facilities, features, not_permitted):
q_objects = []
l_objects = []
t_objects = []
fc_objects = []
ft_objects = []
np_objects = []
if district:
if location:
for loc in location:
l_objects.append(Q(location__exact=loc))
else:
l_objects.append(Q(location__district=district))
if type:
for ty in type:
t_objects.append(Q(listing_type__exact=ty))
if facilities:
for fc in facilities:
fc_objects.append(Q(property_facilities__exact=fc))
if features:
for ft in features:
ft_objects.append(Q(property_features__exact=ft))
ft_objects.append(Q(community_features__exact=ft))
if not_permitted:
for np in not_permitted:
np_objects.append(Q(not_permitted__exact=np))
# Start with a bare QuerySet
qs = self.get_query_set()
if location:
qs = qs.filter(reduce(operator.or_, l_objects))
if type:
qs = qs.filter(reduce(operator.or_, t_objects))
if facilities:
qs = qs.filter(reduce(operator.or_, fc_objects))
if features:
qs = qs.filter(reduce(operator.or_, ft_objects))
if not_permitted:
qs = qs.filter(reduce(operator.or_, np_objects))
# Use operator's or_ to string together all of your Q objects.
return qs
Right now I'm not getting very predictable results. Is there something I might be doing wrong? Is there a better way of doing the various OR searches/joins?
Upvotes: 2
Views: 5608
Reputation: 69
I know this post is a bit old but I came across this, and I assume someone else might when looking for a simple and quick solution,
from django.db.models import Q
from .models import RealEstateListing
def advanced_search(self, community_features, property_features, price, listing, location):
query_dictionary = {
'community_features': community_features,
'property_features': property_features,
'price__lte': price,
'listing_type': listing,
'location': location,
}
# filter out None values
not_none_parameters = {single_query: query_dictionary.get(single_query) for single_query in query_dictionary if query_dictionary.get(single_query) is not None}
filter_list = Q()
for item in not_none_parameters:
filter_list |= Q(**{item:not_none_parameters.get(item)})
qs = RealEstateListing.objects.filter(filter_list)
Upvotes: 1
Reputation: 2913
The closest I've come to this scenario is this post by Jacob:
http://www.djangosnippets.org/snippets/32/
What I've done is:
def advanced_search(self, form):
# It's easier to store a dict of the possible lookups we want, where
# the values are the keyword arguments for the actual query.
qdict = {'district': 'location__district',
'location': 'location',
'property_type': 'listing_type',
'max_price': 'price__lte',
'property_features': 'property_features',
'community_features': 'community_features',
}
# Then we can do this all in one step instead of needing to call
# 'filter' and deal with intermediate data structures.
q_objs = [Q(**{qdict[k]: form.cleaned_data[k]}) for k in qdict.keys() if form.cleaned_data.get(k, None)]
search_results = RealEstateListing.objects.select_related().filter(*q_objs)
return search_results
It works fine when I pass single choices, but when passing multiple choices as for property facilities it chokes and says:
OperationalError: Subquery returns more than 1 row
Upvotes: 2
Reputation: 22248
Just a couple of ideas.
It is very useful to use kwargs unpacking to provide arguments to filter method in such cases. Something like this can make the code simplier:
kwargs = {'not_permitted':np,'property_features': ft}
return qs.filter(**kwargs)
Maybe you should take a look at django's filtering code in admin. In django admin parameters like not_permitted__exact
are passed via GET. And then, after some filtering, the whole GET dict can be passed as unpacked kwargs argument to filter method. This make things really simple when you have a lot of filter options.
Upvotes: 2
Reputation: 552
http://code.google.com/p/djapian/ can index the fields of your choice and allow you build complex searches though combination, boolean logic, etc.
Upvotes: 1