17

我遇到了一个问题,我试图创建一个查询集,其结果不是按模型上的字段排序,而是按模型上的方法返回的值的结果排序。

以机智:

class MyModel(models.Model):

someAttributes = models.TextField(blank=True)

@property
def calculate_rating(self):
<do some calculation and return integer>

鉴于此,我如何构造一个 QuerySet,按由 calculate_rating() 返回的每个实例的值对结果进行排序?

在尝试简单地使用 order_by() 时,我收到一个错误:

无法将关键字“average_rating”解析为字段。

有人可以提供一些想法吗?

4

3 回答 3

19

order_by用于数据库的东西。尝试sorted改用:

sorted(MyModel.objects.all(),  key=lambda m: m.calculate_rating)
于 2013-05-01T16:55:02.847 回答
8

没有办法做到这一点。您可以做的一件事是为该模型创建一个单独的数据库字段并将计算的评分保存在其中。您可能可以覆盖模型的保存方法并在那里进行计算,之后您只能参考该值。

您还可以QuerySet使用对返回的内容进行排序Python sorted。考虑到使用内置 sorted 函数的排序方法会增加很多计算复杂度,在生产中使用这样的代码并不是一个好主意。

有关更多信息,您可以查看此答案:https ://stackoverflow.com/a/981802/1869597

于 2013-05-01T16:59:01.503 回答
3

实现你想要的最好的方法是使用CaseandWhen语句。这允许您保留最终结果QuerySet而不是列表;)

ratings_tuples = [(r.id, r.calc_rating) for r in MyModel.objects.all()]  
ratings_list = sorted(ratings_tuples, key = lambda x: x[1])  # Sort by second tuple elem

所以这是我们的排序列表ratings_list,它以排序的方式保存元素的 ID 和评级

pk_list = [idx for idx, rating in ratings_list]  
from django.db.models import Case, When
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pk_list)])  
queryset = MyModel.objects.filter(pk__in=pk_list).order_by(preserved)  

现在,使用CaseandWhen语句,我们可以通过我们已经拥有的列表中的 ID 对查询集进行排序。(Django Docs 了解详情)。
有类似的情况,需要一个解决方案。所以在这篇文章https://stackoverflow.com/a/37648265/4271452上找到了一些细节,它可以工作。

于 2018-11-10T00:03:00.817 回答