按Django查询集中的字符串匹配数排序

时间:2015-09-11 20:51:13

标签: python django django-queryset

我的模型有一个标记字段,这是一个以逗号分隔的标记列表。给定一个标签字符串列表,我构建了一个查询集,用于查找至少包含其中一个标签的模型实例。我有这样的工作:

tag_list = ["tag1", "tag2"]

MyModel.objects.filter(
    reduce(
        lambda x, y: x | y, [Q(tags__icontains=tag) for tag in tag_list]))

但是现在我想按每个项目的数字匹配标记按递减顺序对查询集进行排序。我一直试图找到一个正确的方法来注释一个包含匹配数字的字段但是没有多少运气。有什么指针吗?

2 个答案:

答案 0 :(得分:0)

我认为在python而不是数据库中进行排序会更加高效。获得至少有一个标记的list个对象后,可以使用传递给排序比较的MyModel.tags.count()属性对其进行排序 - 它就像基于对象列表排序一样在整数字段

# your query
objects = MyModel.objects.filter('...')

# sort in place
objects.sort(
    # set the sorting comparison to tag count
    key = lambda obj: obj.tags.count(),
    # if you want a descending comparison, highest tag count first
    # reverse = True
)

我说这会更效率,因为我假设您将继续使用所有对象,而不是说,只是获得第一个(具有最高标签数)。因此,不是让数据库进行比较,而是可以在python本身中完成。

答案 1 :(得分:0)

我想出了一个(复杂的)解决方案:

from django.db.models import Case, ExpressionWrapper, IntegerField, Q, Value, When

tag_list = ["tag1", "tag2"]

qs = MyModel.objects.filter(
    reduce(
        lambda x, y: x | y, [Q(tags__icontains=tag) for tag in tag_list]))

check_matches = map(
    lambda x: Case(
        When(Q(tags__icontains=x), then=Value(1)),
            default=Value(0)),
    tag_list)
count_matches = reduce(lambda x, y: x + y, check_matches)
qs = qs.annotate(
    matches=ExpressionWrapper(
        count_matches,
        output_field=IntegerField()))
qs = qs.order_by('-matches')