views:

236

answers:

3

I want to look for a certain string in several fields of a Model in Django. Ideally, it would go something similar to:

keyword = 'keyword'
fields = ['foo', 'bar', 'baz']
results = []
for field in fields:
    lookup = "%s__contains"
    results.append(Item.objects.filter(lookup=keyword))

Of course this won't work, as "lookup" can't be resolved into a field. Is there any other way to do this?

+2  A: 

I think there may be a better way to do this with the Django query system. Here's how to do it your way.

Python allows you to pass dictionaries to be used as argument lists by prefixing them with **. With a spot of luck, you should be able to do something like this:

lookup = "%s__contains" % field
results.append(Item.objects.filter(**{ lookup: keyword}))
Dial Z
Have a look at Botondus's answer below. It's the solution with the Django query system that I referred to, and it should hopefully run faster since it'll execute in SQL.
Dial Z
+2  A: 

I like DialZ's answer but for performance reasons you should build the query and then hit the database once instead of concatenating all the results into a list:

keyword = 'keyword'
fields = ['foo', 'bar', 'baz']

# this makes an empty queryset object which we can
# add to later using the | operator
results = Item.objects.none()

for field in fields:
    lookup = "%s__contains" % field
    query = {lookup : keyword}
    results = results | Item.objects.filter(**query)

I havn't done one of these in a while, but I'm pretty sure django will not actually hit the database at all in this code. It will only perform a query when you access the data contained in the records

Jiaaro
+2  A: 

I would prefer to use the Q object for something like this.

from django.db.models import Q

keyword = 'keyword'
fields = ['foo', 'bar', 'baz']

Qr = None
for field in fields:
    q = Q(**{"%s__contains" % field: keyword })
    if Qr:
        Qr = Qr | q # or & for filtering
    else:
        Qr = q

# this you can now combine with other filters, exclude etc.    
results = MyModel.objects.filter(Qr)
Béres Botond