django icontains with __in lookup

This is the approach that I adopted:

class MyManager(models.Manager):
    def exclusive_in(self, lookup, value_list):
        return self.filter(reduce(or_, (Q(**{lookup:_}) for _ in value_list)))

Here is now to use it:

Companies.objects.exclusive_in('name__icontains', possible_merchants])

It was inspired by other answers in this thread, as well as Django filter queryset __in for *every* item in list.


You can create querysets with the Q constructor and combine them with the | operator to get their union:

from django.db.models import Q

def companies_matching(merchants):
    """
    Return a queryset for companies whose names contain case-insensitive
    matches for any of the `merchants`.
    """
    q = Q()
    for merchant in merchants:
        q |= Q(name__icontains = merchant)
    return Companies.objects.filter(q)

(And similarly with iexact instead of icontains.)


I find it a cleaner approach using reduce and or_ operator:

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

def get_companies_from_merchants(merchant_list):
    q_object = reduce(or_, (Q(name__icontains=merchant) for merchant in merchant_list))
    return Companies.objects.filter(q_object)

This would create a list of Q objects querying the name to contain a single element in merchant list. This would happpen for all the elements in merchant_list and all these Q objects would be reduced to a single Q object having mutliple ORs which can be directly applied to the filter query.

Tags:

Python

Django