过滤具有可变参数数的多个Django模型字段
我正在实现搜索功能,可以通过匹配多个表和这些表中的多个字段来查找记录 假设我想根据客户的名字或姓氏,或者根据下单的ID查找客户,下单的ID存储在与客户不同的型号中。 我已经实现的简单场景是,用户只在搜索字段中键入单个单词,然后使用Django过滤具有可变参数数的多个Django模型字段,django,django-queryset,django-q,Django,Django Queryset,Django Q,我正在实现搜索功能,可以通过匹配多个表和这些表中的多个字段来查找记录 假设我想根据客户的名字或姓氏,或者根据下单的ID查找客户,下单的ID存储在与客户不同的型号中。 我已经实现的简单场景是,用户只在搜索字段中键入单个单词,然后使用DjangoQ使用直接字段引用或related\u query\u name引用来查询Order模型,如: result = Order.objects.filter( Q(customer__first_name__icontains=user_inp
Q
使用直接字段引用或related\u query\u name
引用来查询Order
模型,如:
result = Order.objects.filter(
Q(customer__first_name__icontains=user_input)
|Q(customer__last_name__icontains=user_input)
|Q(order_id__icontains=user_input)
).distinct()
小菜一碟,一点问题也没有
但是,如果用户想要缩小搜索范围并在搜索字段中键入多个单词,该怎么办呢
示例:用户键入了Bruce
,并通过搜索返回了大量记录
现在,他/她希望更具体一些,并在搜索中添加客户的姓氏。因此,搜索变成了Bruce Wayne
,在将其拆分为我的Bruce
和Wayne
的单独部分之后。显然,我不想搜索订单
模型,因为order\u id
是一个单词实例,一次找到客户就足够了,所以在这种情况下,我将其从查询中删除
现在,我试图通过名字和姓氏匹配客户,我还想处理提供数据的顺序是随机的情况,以正确处理Bruce Wayne
和Wayne Bruce
,这意味着我仍然有客户全名,但名字和姓氏的位置不固定
这就是我要寻找答案的问题:如何构建一个查询来搜索模型的多个字段,而不知道哪个搜索词属于哪个表
我猜这个解决方案很简单,肯定有一种优雅的方法可以创建这样一个动态查询,但我想不出一种方法。您可以动态地或可变数量的Q对象组合在一起,以实现所需的搜索。下面的方法使得添加或删除要包含在搜索中的字段变得非常简单
from functools import reduce
from operator import or_
fields = (
'customer__first_name__icontains',
'customer__last_name__icontains',
'order_id__icontains'
)
parts = []
terms = ["Bruce", "Wayne"] # produce this from your search input field
for term in terms:
for field in fields:
parts.append(Q(**{field: term}))
query = reduce(or_, parts)
result = Order.objects.filter(query).distinct()
使用
reduce
将Q对象组合在一起。要归功于答案的这一部分。您可以动态或可变数量的Q对象组合在一起,以实现所需的搜索。下面的方法使得添加或删除要包含在搜索中的字段变得非常简单
from functools import reduce
from operator import or_
fields = (
'customer__first_name__icontains',
'customer__last_name__icontains',
'order_id__icontains'
)
parts = []
terms = ["Bruce", "Wayne"] # produce this from your search input field
for term in terms:
for field in fields:
parts.append(Q(**{field: term}))
query = reduce(or_, parts)
result = Order.objects.filter(query).distinct()
使用
reduce
将Q对象组合在一起。要归功于答案的这一部分。我提出的解决方案相当复杂,但它的工作方式正是我想要处理这个问题的方式:
search_keys = user_input.split()
if len(search_keys) > 1:
first_name_set = set()
last_name_set = set()
for key in search_keys:
first_name_set.add(Q(customer__first_name__icontains=key))
last_name_set.add(Q(customer__last_name__icontains=key))
query = reduce(and_, [reduce(or_, first_name_set), reduce(or_, last_name_set)])
else:
search_fields = [
Q(customer__first_name__icontains=user_input),
Q(customer__last_name__icontains=user_input),
Q(order_id__icontains=user_input),
]
query = reduce(or_, search_fields)
result = Order.objects.filter(query).distinct()
我提出的解决方案相当复杂,但它的工作方式正是我想要处理这个问题的方式:
search_keys = user_input.split()
if len(search_keys) > 1:
first_name_set = set()
last_name_set = set()
for key in search_keys:
first_name_set.add(Q(customer__first_name__icontains=key))
last_name_set.add(Q(customer__last_name__icontains=key))
query = reduce(and_, [reduce(or_, first_name_set), reduce(or_, last_name_set)])
else:
search_fields = [
Q(customer__first_name__icontains=user_input),
Q(customer__last_name__icontains=user_input),
Q(order_id__icontains=user_input),
]
query = reduce(or_, search_fields)
result = Order.objects.filter(query).distinct()
这回答了部分与动态生成查询相关的问题,但可能我没有把问题讲清楚,所以我更新了问题。这回答了部分与动态生成查询相关的问题,但可能我没有把问题讲清楚,所以我更新了问题。