3

I'm trying to implement a search in a django sqlite db.

I get a list of unknown length of params which should all be matched with a 'LIKE'. This means I want all objects that match at least one of the params.

As I can see from the django docs I can reach this by using the Q object.

Example:

Students.objects.get(
    Q(name_contains='franz') | 
    Q(birthdate_date=date(2005, 5, 2) | 
    Q(param3_contains='lorem'
)

Now my question is, how can I handle it to join all the Q objects created from params to pass as arguments to the objects.get(). I could not find any on this.

Another issue here is to handle several different Field Lookup types.

I appreciate any advice, help or helping links you can give. Thank you.

Tomasz Jakub Rup
  • 10,502
  • 7
  • 48
  • 49
Igl3
  • 4,900
  • 5
  • 35
  • 69
  • not clear on what you mean by "joining the Q objects", if you're trying to AND them together you can just use [`&`](https://docs.djangoproject.com/en/1.8/ref/models/querysets/#q-objects). Also your example seems to have incorrect field lookup syntax, it should be something like `name__contains` with two underscores. – Yeray Diaz Sep 14 '15 at 15:11
  • I mean I dont know which params I get. So it could be 2, 3 or also 7 params. I kind of have to iterate through them, put them in Q objects and then pass them as arguments to my get function. But I don't know how I join these arguments together with |. So i explicitely want to use OR. – Igl3 Sep 14 '15 at 15:13
  • Check my answer to similar question in this thread: https://stackoverflow.com/a/65720209/4313735 – michal-michalak Jan 14 '21 at 13:49

2 Answers2

12

If you want to dynamically build the list of queries, you could have a sequence like this:

request = Q(name_contains='franz')

if condition1:
  request |= Q(birthdate_date=date(2005, 5, 2))

if condition2:
  request |= Q(param3_contains='lorem')

Then:

Students.objects.get(request)

If you need something even more generic, you could have a function that passes a dict, like:

conditions = {'name_contains': 'franz',
              'birthdate_date': date(2005, 5, 2),
              'param3_contains': 'lorem'}

And build the condition like this (Untested):

request = None
for key, value in conditions.items():
  new_request = Q(**{key: value})

  if request: request |= new_request
  else: request = new_request
Dric512
  • 3,525
  • 1
  • 20
  • 27
  • yes and also need to add `.items()` at the end of `conditions` to avoid `too many values to unpack ` exception. like this. `for key, value in conditions.items():` – Alireza Saremi Jul 21 '19 at 07:03
1

I have a similar requirement in my application. I have to search for a searchterm in all kinds of names:

Qterm = Q(firstname__icontains=searchterm) | \
        Q(lastname__icontains=searchterm) | \
        Q(resume__icontains=searchterm) | \
        Q(companyname__icontains=searchterm))

or, if you want to match one field to a number of searchterms:

Qterm = Q()
for term in ["robot", "animatronic", "automaton"]:
    Qterm |= Q(rolename_icontains=term)

fieldname_icontains ultimately becomes a LIKE. There are also more criteria, like that the user should be 'active', which is a boolean field:

Qactive = Q(active=True)

At the end, I combine all these Q objects like this:

Qs = Qterm & Qactive & Qthis & Qthat 

...and I retrieve my active users like this:

userlst = Users.objects.filter(Qs)

I hope this helps!

Michiel Overtoom
  • 1,609
  • 13
  • 14