使用__in查找django icontains

时间:2012-03-12 20:56:22

标签: python django

所以我想在某些字段中找到任何类型的匹配,例如,这就是我想要做的事情:

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

遗憾的是,无法混合icontains和__in查找。

这似乎是一个非常复杂的查询,所以如果至少我可以忽略大小足够的名称,例如:

Companies.objects.filter(name__ignorecase__in=possible_merchants)

有什么想法吗?

P.D。:我发布的查询不起作用,这只是一种表达我需要的方式(以防万一)

4 个答案:

答案 0 :(得分:25)

您可以创建查询集with the Q constructor并将它们与|运算符组合以获得它们的联合:

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)

(类似于iexact而不是icontains。)

答案 1 :(得分:1)

我发现它使用reduceor_运算符是一种更干净的方法:

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)

这将创建Q个对象的列表,这些对象查询name以在商家列表中包含一个元素。这将发生merchant_list中的所有元素,并且所有这些Q对象将被简化为具有多个或可以直接应用于过滤器查询的单个Q对象。

答案 2 :(得分:0)

这是我采用的方法:

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

现在在这里使用它:

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

它是受此主题中其他答案以及Django filter queryset __in for *every* item in list启发的。

答案 3 :(得分:0)

另一种方法是模拟 Django 通常对 iexact 查询执行的操作(它通过 SQL Upper 函数将比较语句的两部分都转换为大写。

这样,查询将如下所示:

Companies.objects.annotate(
    upper_name=models.Upper("name")
).filter(
    upper_name__in=[rchant.upper() for merchant in possible_merchants]
)