dxb
dxb

Reputation: 283

Find a string in the entire table (all fields, all columns, all rows) in Django

I have a module (table) in my Django app with 24 fields (columns), and I want to search a string in it. I want to see a list that show me which one of the rows has this string in its fields.

Please have a look at this example:

+-----+------+------+---------+------------+------------+------------+-----+-------------+
| id  | name | year | country | attribute1 | attribute2 | attribute3 | ... | attribute20 | 
+-----+------+------+---------+------------+------------+------------+-----+-------------+
| 1   | Tie  | 1993 | USA     | Bond       | Busy       | Busy       | ... | Free        |
+-----+------+------+---------+------------+------------+------------+-----+-------------+
| 2   | Ness | 1980 | Germany | Free       | Busy       | Both       | ... | Busy        |
+-----+------+------+---------+------------+------------+------------+-----+-------------+
| 3   | Both | 1992 | Sweden  | Free       | Free       | Free       | ... | Busy        |
+-----+------+------+---------+------------+------------+------------+-----+-------------+
| ... | ...  | ...  | ...     | ...        | ...        | ...        | ... | ...         |
+-----+------+------+---------+------------+------------+------------+-----+-------------+
| 24  | Lex  | 2001 | Russia  | Busy       | Free       | Free       | ... | Both        |
+-----+------+------+---------+------------+------------+------------+-----+-------------+

What I am looking to get (by using filters, etc.) is something like this: (When I filter the records base on the word "Both" in the entire table and all of the records. Each row that contains "Both" is in the result below)

+----+------+------+---------+------------+------------+------------+-----+-------------+
| id | name | year | country | attribute1 | attribute2 | attribute3 | ... | attribute20 |
+----+------+------+---------+------------+------------+------------+-----+-------------+
| 1  | Ness | 1980 | Germany | Free       | Busy       | Both       | ... | Busy        |
+----+------+------+---------+------------+------------+------------+-----+-------------+
| 2  | Both | 1992 | Sweden  | Free       | Free       | Free       | ... | Busy        |
+----+------+------+---------+------------+------------+------------+-----+-------------+
| 3  | Lex  | 2001 | Russia  | Busy       | Free       | Free       | ... | Both        |
+----+------+------+---------+------------+------------+------------+-----+-------------+

You can see that the string ("Both") appears in different rows in different columns. (one "Both" is under the column "attribute3", the other "Both" is under column "Name", and the last "Both" is under column "attribute20".

How you get this result in Django by queryset?

Thanks

Upvotes: 0

Views: 1311

Answers (1)

bhaskarc
bhaskarc

Reputation: 9521

Assuming you have modeled the above table as a Django model named Person

from django.db.models import Q

query_text = "your search string"
Person.objects.filter(
    Q(name__contains=query_text) |
    Q(year__contains=query_text) |
    Q(attribute1__contains=query_text)
and so on for all your attributes
)

The above code will do a case sensitie search. if instead you want it to be case insenssitive search, use name__icontains instead of say name__contains in the above code.

As suggested by @rchurch4 in comment and based on this so answer, here's how one could search the entire table with fewer lines of code:

from functools import reduce
from operators import or_
all_fields = Person._meta.get_fields()
search_fields = [i.name for i in all_fields]
q = reduce(or_, [Q(**{'{}__contains'.format(f): search_text}) for f in search_fields], Q())
Person.objects.filter(q)

Upvotes: 2

Related Questions