Django自定义order_by算法



我想创建一个趋势帖子的公式。到目前为止,我已经做到了:

def hot(request):
posts = Post.objects.all()
for post in posts:
likes = int(post.likes)
views = int(post.blog_view)
rep = int(post.author.profile.reputation)
d0 = timezone.now()
d1 = post.date_posted
days = (d0 - d1).days
trending_score = (3/(1+days**(1/3)))*(0.5*views+0.25*rep+2.5*likes)

该公式处于trending_score变量,每次它都会返回其趋势得分的数字。trending_score越高,趋势性越强。

现在我想使用order_by或其他东西在django中实现这一点:

def hot(request):
posts = Post.objects.all()
for post in posts:
likes = int(post.likes)
views = int(post.blog_view)
rep = int(post.author.profile.reputation)
d0 = timezone.now()
d1 = post.date_posted
days = (d0 - d1).days
trending_score = (3/(1+days**(1/3)))*(0.5*views+0.25*rep+2.5*likes)
context = {
Post.objects.all().order_by(-trending_score)
}
return render(request, 'blog/popularity.html', context)

我显然知道这不会起作用,因为我把trending_score放在for循环中,上下文在它之外,所以它不会起作用。错误是:Invalid order_by arguments: [-21.75]但我不知道还能怎么做。如有任何帮助,我们将不胜感激。

您可以用公式计算的值对查询集进行注释,然后根据注释对其进行排序。最重要的是将您的公式转换为django-ORM所理解的表示形式,以便将其转换为正确的SQL语句。像这样的东西应该起作用:

from django.db.models import F, FloatField, DurationField
from django.db.models.functions import Cast, Now, Extract

days = Cast(
Extract(Cast(Now() - F('date_posted'), DurationField()), 'days'),
FloatField()
)
views = Cast('views', FloatField())
rep = Cast('post.author.profile.reputation', FloatField())
likes = Cast('likes', FloatField())
Post.objects.all().annotate(
trending_score=(3./(1+days**(1/3)))*(.5*views+.25*rep+2.5*likes)
).order_by('-trending_score')

我能想到的最简单的修复方法是创建一个新的列表来存储结果。这将允许您在不必更改模型或任何内容的情况下,按特定属性排序结果。

def hot(request):
posts = Post.objects.all()
result = []
for post in posts:
likes = int(post.likes)
views = int(post.blog_view)
rep = int(post.author.profile.reputation)
d0 = timezone.now()
d1 = post.date_posted
days = (d0 - d1).days
trending_score = (3/(1+days**(1/3)))*(0.5*views+0.25*rep+2.5*likes)
result.append((trending_score, post))  #added a tuple of value-object
context = {
sorted(result, reverse=True)
}
return render(request, 'blog/popularity.html', context)

在HTML页面上,而不是

{% for post in posts %}

你可以使用

{% for object in posts %}
post = object[1]

最新更新