按Q()或匹配项的数量排序Django查询结果

时间:2019-12-08 04:06:20

标签: python django

我在一个查询集中有很多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()和注释是否可行。有谁知道我怎么能做到这一点?

2 个答案:

答案 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