使用有价值的过滤器优先处理对象

时间:2016-07-12 22:52:20

标签: python django postgresql filter

我有一个有趣的编程问题,我确信它有许多非常有趣的解决方案,我希望有人能够深入了解我可以采取的良好方向。

我在Django工作,我有一个对象QuerySet和一组过滤器。我想找到一个在所有过滤器中存活的对象子集,但这并不总是可行的,所以我想对查询集进行排序,以便在最重要的过滤器之后存在的对象总是会被过滤掉。我为每个过滤器定义了重要性级别。

所以,在一个抽象的层面上,给定一组对象和一组加权约束,我想要一个有序的对象列表,通过它们实现的权重。

例如, 给出一组单词:

{'Almond', 'Red', 'Apple', 'Gargle', 'Anyone'}

一组有价值的过滤器:

- Starts with A, worth 10 points

- Ends with E, worth 5 points

- 6 letters long, worth 3 points

返回以下数组,并带有相关的得分:

[['Anyone',18],['Apple',15],['Almond', 13],['Gargle',8],['Red',0]]

由于这些是Django中的对象和过滤器,我还想使用尽可能查询集函数而不是循环来改善运行时和复杂性(我正在使用PostgreSQL,因此任何PostgreSQL特定的解决方案都可以)。 基本上,如果我有n个对象和f过滤器,我希望实现比O(nf+nlogn)更好的复杂性,或者至少优化Django的解决方案。

1 个答案:

答案 0 :(得分:2)

from django.db.models import CharField, IntegerField, Case, When, Q
from django.db.models.functions import Length

# You can register function as a transform
CharField.register_lookup(Length, 'length')

filters = [
    (Q(name__startswith='A'), 10),
    (Q(name__endswith='E'), 5),
    (Q(name__length=6), 3),
]

Item.objects.annotate(
    # sum, not Sum
    tot_score=sum(Case(When(filter, then=score),
                       default=0,
                       output_field=IntegerField())
                  for filter, score in filters)
).values_list('name', 'tot_score').order_by('-tot_score')

Conditional Expressions