Question

This question already has an answer here:

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?

Was it helpful?

Solution

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}))

OTHER TIPS

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)

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top