我在一个查询集中有很多Q()OR条件,并且需要根据匹配的Q()中的多少对查询集进行排序。例如:
SELECT x.id_lib, (
SELECT sg.nom FROM subgenres sg WHERE (x.id_gen = sg.id)
)as genname, x.id_gen
FROM subgenres_books x WHERE x.id_lib = 1 and genname LIKE 'Satira'
这将返回所有在 title description 或 body 中具有 word 的对象的查询集列表。但是我要按多少个Q()过滤器匹配来对queryset列表进行排序。如果对象在所有3个字段中都具有 word ,则应首先列出该对象,然后在2个字段中具有 word 的字段,依此类推。我的第一个想法是以某种方式向每个递增的Q()添加一个annotate(),并以此进行排序。但是我不确定Q()和注释是否可行。有谁知道我怎么能做到这一点?
答案 0 :(得分:0)
我的解决方案很复杂,但希望它将解决您的问题,
for obj in q_objects:
if obj in q_in_title and obj in q_in_description and obj in q_in_body:
q_ordered += obj
for obj in q_objects:
if ( obj in q_in_title and obj in q_in_description ) or ( obj in q_in_description and obj in q_in_body ) or ( obj in q_in_title and obj in q_in_body):
q_ordered += obj
for obj in q_objects:
if obj in q_in_title or obj in q_in_description or obj in q_in_body:
q_ordered += obj
您也可以使用
q_ordered += [obj for obj in q_objects if obj in q_in_title and obj in q_in_description and obj in q_in_body]
q_ordered += [obj for obj in q_objects if ( obj in q_in_title and obj in q_in_description ) or ( obj in q_in_description and obj in q_in_body ) or ( obj in q_in_title and obj in q_in_body)]
q_ordered += [obj for obj in q_objects if obj in q_in_title or obj in q_in_description or obj in q_in_body]
代替使用
{{1}}
答案 1 :(得分:0)
Django的聚合函数接受过滤器argument(请参阅备忘单)。我们可以将已经创建的Q对象重新用作过滤器,以计算这些过滤器发生了多少次。请查看对过滤器进行计数的每个注释。
然后将这些过滤器计数和order_by相加。
我尚未测试此代码,因此希望它对您有用。
from django.db.models import Count
def get_queryset(self, *args, **kwargs):
qs = super().get_queryset(*args, **kwargs)
word = self.request.GET.get('q') # from search input
title = Q(title__icontains=word)
description = Q(description__icontains=word)
body = Q(body__icontains=word)
filters = title | description | body
qs = (qs
.filter(filters)
.annotate(title_filter_cnt=Count('id', filter=title))
.annotate(description_filter_cnt=Count('id', filter=description))
.annotate(body_filter_cnt=Count('id', filter=body))
.annotate(total_filter_cnt=F('title_filter_cnt') +
F('description_filter_cnt') +
F('body_filter_cnt'))
.order_by('total_filter_cnt'))
return qs