views:

40

answers:

2

I'm trying to perform a case-insensitive query. I would generally use __icontains, but since it doesn't support the .split() method, I'm stuck to using __in instead:

def search(request):
    query = request.GET.get('q', '')
    query = query.lower()
    product_results = []
    category_results = []
    if query:
        product_results =  Product.objects.filter(Q(title__in=query.split())|
                                                   Q(brand__in=query.split())|
                                                   Q(description__in=query).split())
        category_results = Category.objects.filter(title__in=query.split())

My problem is that the object fields usually have a the first letter capitalized, so an all lowercase query always returns negative.

Anyway around this?

+1  A: 

I have solved this problem by using exec to generate code from a string using icontains instead of in. I admit, it's sloppy and not elegant, and should be audited for security but it worked.

see the untested/pseudocode:

query = "product_results =  Product.objects.filter("
for word in words:
    query += "Q(title__icontains(word))|"
    query += "Q(brand__icontains(word))|"
    query += "Q(description__icontains(word))|"
query = query[:-1] # remove the trailing |
query += ")"
exec("product_results = "+query)

Again, this is probably not advisable, and I'm sure there's a better way to do this, but this fixed me up in a pinch once so I thought I would share. Also note, I don't use this code anymore as I've switched over to sqlalchemy which makes these kinds of dynamic queries a bit easier since it's "or" object accepts a list.

andyortlieb
+1  A: 

thanks for sharing, i wrote up this quick hack, not elegant at all....

def search(request):
    query = request.GET.get('q', '')
    query = query.split()
    product_results = []
    category_results = []
    if query:
        for x in query:
            product_results.extend(Product.objects.filter(Q(title__icontains=x)|
                                                       Q(brand__icontains=x)|
                                                       Q(description__icontains=x)))
            category_results.extend(Category.objects.filter(title__icontains=x))
    query = request.GET.get('q', '')
    product_results = list(set(product_results))
    category_results = list(set(category_results))
    return render_to_response('search_results.html', {'query': query,
                                                      'product_results': product_results,
                                                      'category_results': category_results})
momo
Ah I overlooked extend. kudos
andyortlieb