首页 > 解决方案 > 将关键字存储在查询集中,在结果查询集中提供带有 Q 对象的搜索命中以及搜索结果

问题描述

record_list是一个 Python 列表,其中包含要搜索的关键字列表。以下代码是我的 Django views.py,我在其中使用这些关键字搜索 MySQL 数据库。代码在列中搜索product_namedescription返回关键字给出搜索命中的整个记录​​。

q_object = Q(product_name__icontains=record_list[0]) | Q(description__icontains=record_list[0])
for item in record_list:
   q_object.add(Q(product_name__icontains=item) & (Q(description__icontains=item)), q_object.connector)
    
queryset = Products.objects.filter(q_object).values().distinct()
    
for query in queryset:
   Filtered.objects.create(**query)

搜索结果成功保存queryset在数据库表中,我可以将查询集保存在数据库表中。但我还想将在“查询集”中提供搜索命中的关键字与相应的搜索结果一起保存。有没有办法使用 Django Q 对象来做到这一点?

标签: pythondjangodjango-querysetdjango-q

解决方案


我建议仅通过 Python 评估等效的 Q() 表达式。最后我会解释为什么。

预计模型Filtered有一个 CharFieldkeywords并且关键字由一个字符分隔,该字符绝不是关键字的一部分,例如空格或逗号。

q_object = ~Q()  # trick: a filter with empty results
for item in record_list:
   q_object |= Q(product_name__icontains=item) | (Q(description__icontains=item))

queryset = Products.objects.filter(q_object).values().distinct()

new_items = []
for item_dict in queryset:
    used_keywords = [keyword for keyword in record_list
                     if keyword.lower() in item_dict['product_name'].lower() or
                     if keyword.lower() in item_dict['description'].lower()]
    new_items.append(Filtered(keywords=used_keywords, **item_dict))
Filtered.objects.bulk_create(new_items)

代码注释:

  • 您的代码的最后一部分通过bulk_create()方法而不是 simple进行了优化create()

  • 显式 OR 连接器 ('|=') 优于q_object.connector在阅读更多代码后必须最终识别为 OR 的间接连接器。

  • .values()如果您不使用连接,则组合是没有用的.distinct(),因为主键字段也是 values() 字段的一部分,并且主键在仅基于一个表的查询集中是唯一的。我没有删除它,因为可能一个连接隐藏在record_list可能被更多表遍历的 a 中。

为什么Q 对象不能直接评估匹配的关键字?因为 WhereNode 不能直接在 Python 中进行评估,除非通过 SQL 单独执行它们,否则它们不能成为 SQL 中 SELECT 子句的一部分。Q 表达式非常通用且可扩展,例如通过具有许多变量的用户定义函数。因此,仅针对简单类型的表达式在 Django 中实现 Python 评估是没有意义的。通过 SQL 对每个关键字进行评估是无效的,但对于运行测试来说,SQL 和 Python 实现的结果对于某些测试用例集或在调试模式下是相同的仍然很有用,特别是如果您稍后将编辑这些 Q 表达式.


推荐阅读