Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django icontains with __in lookup

Tags:

django

So I want to find any kind of matching given some fields, so for example, this is what I would like to do:

possible_merchants = ["amazon", "web", "services"]
# Possible name --> "Amazon Service"
Companies.objects.filter(name__icontains__in=possible_merchants)

sadly it is not possible to mix icontains and the __in lookup.

It seems to be a pretty complex query so if at least I could ignore case the name that would be enough, for example:

Companies.objects.filter(name__ignorecase__in=possible_merchants)

Any ideas?

P.D.: The queries I posted don't work, it's just a way to express what I need (just in case heh)

like image 759
Hassek Avatar asked Mar 12 '12 20:03

Hassek


People also ask

What is __ Icontains in Django?

Definition and Usage. The icontains lookup is used to get records that contains a specified value. The icontains lookup is case insensitive. For a case sensitive search, use the contains lookup.

What is the difference between contains and Icontains in Django?

Definition and Usage The contains lookup is used to get records that contains a specified value. The contains lookup is case sensitive. For a case insensitive search, use the icontains lookup.

What is Select_related in Django?

Django offers a QuerySet method called select_related() that allows you to retrieve related objects for one-to-many relationships. This translates to a single, more complex QuerySet, but you avoid additional queries when accessing the related objects. The select_related method is for ForeignKey and OneToOne fields.


3 Answers

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

like image 84
Gareth Rees Avatar answered Oct 06 '22 22:10

Gareth Rees


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.

like image 40
Sanyam Khurana Avatar answered Oct 06 '22 22:10

Sanyam Khurana


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.

like image 32
caram Avatar answered Oct 06 '22 22:10

caram