neolaser
neolaser

Reputation: 6907

Django: Query using contains each value in a list

I need to perform a django query that checks if a field contains all values within a list. The list will be of varying length

Example

User.objects.filter(first_name__contains=['x','y','z'])

Upvotes: 82

Views: 60091

Answers (8)

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798744

import operator
from django.db.models import Q
from functools import reduce

User.objects.filter(
    reduce(operator.and_, (Q(first_name__contains=x) for x in ['x', 'y', 'z']))
)

For python 2 you did not need to import reduce.

Upvotes: 137

user2872619
user2872619

Reputation: 401

import operator
from django.db.models import Q
from functools import reduce
    
q = ['x', 'y', 'z']
query = reduce(operator.and_, (Q(first_name__contains = item) for item in q))
result = User.objects.filter(query)

Upvotes: 40

Mark Mishyn
Mark Mishyn

Reputation: 4151

More readable solution.

qs = User.objects.all()
for search_term in ('x', 'y', 'z'):
    qs = qs.filter(first_name__contains=search_term) 

Note: Querysets are lazy, so this code makes 1 DB query.

Upvotes: 7

Rodut Naitsirc
Rodut Naitsirc

Reputation: 31

the_list= []

data_list= ['x', 'y', 'z'] 

for i in data_list:

    a = User.objects.filter(first_name__contains=project).values('etc')

    the_list+= a

Upvotes: 1

vpap
vpap

Reputation: 1547

It doesn't apply exactly here, but, if you have a ManyToManyField and you want to check if it contains a specific value, check this https://www.revsys.com/tidbits/tips-using-djangos-manytomanyfield/.

I have a "Products" and Django native "Users" model. My "Products" model has a many-to-many field users pointing to "Users". Then, I wanted to check if this list-like field contained the logged in user. I did that by ...users__username_icontains=request.user.username... and the link above helped me to understand better what is a many-to-many field and how it works.

Upvotes: 0

Baasje85
Baasje85

Reputation: 11

This worked for me in django 2.2, python 3.8, using lambda instead of 'operator'. Explanations on lambda can be found here: https://www.python-course.eu/lambda.php

from functools import reduce
from django.db.models import Q

my_list = ['x','y','z']
User.objects.filter(reduce(lambda x, y: x & y, [Q(first_name__contains= i for i in my_list]))

Upvotes: 0

AltoBalto
AltoBalto

Reputation: 401

The accepted solution didn't work for me, but this did:

list = ['x', 'y', 'z']
results = User.objects.filter(first_name__contains=list[0])
del list[0]

for l in list:
    results = results.filter(first_name__contains=l)

The first results variable will store a list of all the objects with the first_name name field value 'x'.

And then in the for loop you filter for 'y' amongst the first filter results. Now you have a QuerySet that should contain a list of items where both 'x' and 'y' can be found. Now amongst those you filter for any item that contains 'z' as well.

This should work for any length list.

Upvotes: 2

Michel Dudouze
Michel Dudouze

Reputation: 11

from django.db.models import Q
User.objects.filter(Q(first_name__contains=x)&Q(first_name__contains=y)&Q(first_name__contains=z))

Works for me on Django 1.8 python 2.7

doc => https://docs.djangoproject.com/en/1.8/ref/models/querysets/#q-objects

for more recent => https://docs.djangoproject.com/en/2.1/ref/models/querysets/#q-objects

Upvotes: 1

Related Questions