Django order_by一个属性

时间:2013-05-01 16:45:19

标签: django django-models

我遇到了一个问题,我正在尝试创建一个QuerySet,其结果不是由模型上的字段排序,而是由模型上的方法返回的值的结果排序。

即便:

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'解析为字段。

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

3 个答案:

答案 0 :(得分:11)

order_by用于数据库内容。请尝试使用sorted代替:

sorted(MyModel.objects.all(),  key=lambda m: m.calculate_rating)

答案 1 :(得分:4)

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

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

有关详情,请查看以下答案:https://stackoverflow.com/a/981802/1869597

答案 2 :(得分:1)

实现所需目标的最佳方法是使用CaseWhen语句。这使您可以将最终结果保留在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)  

现在,使用CaseWhen语句,我们就可以根据已经拥有的列表中的ID进行查询集自身的排序。 (Django Docs for details)。
遇到类似情况,需要解决方案。因此,在此帖子https://stackoverflow.com/a/37648265/4271452中找到了一些详细信息,它可以正常工作。