简体   繁体   English

Django 自定义 order_by 算法

[英]Django custom order_by algorithm

I want to create a formula for trending posts.我想为热门帖子创建一个公式。 I've done this so far:到目前为止,我已经这样做了:

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)

The formula is at trending_score variable, and each time, it returns a number for its trending score.该公式位于trending_score 变量中,每次都会返回一个数字作为其趋势得分。 The higher the trending_score, the more trending it is. Trending_score 越高,趋势越明显。

Now I want to implement this in django using order_by, or something else:现在我想使用 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)

I obviously knew this wasn't going to work, because I put trending_score in the for loop and context is outside of it, so it wasn't going to work.我显然知道这行不通,因为我将trending_score 放在for 循环中,而上下文在它之外,所以它行不通。 The error was: Invalid order_by arguments: [-21.75] But I have no idea how else I can do this.错误是: Invalid order_by arguments: [-21.75]但我不知道我还能怎么做。 Any help in doing this will be appreciated.对此的任何帮助将不胜感激。

You can annotate your queryset with values calculated by your formula and then order it based on the annotation.您可以使用公式计算的值来注释查询集,然后根据注释对其进行排序。 The main thing is to translate your formula to the representation that django ORM understands such that it would convert to a proper SQL statement.主要是将您的公式转换为 django ORM 理解的表示形式,以便它将转换为正确的 SQL 语句。 Something like this should work:像这样的东西应该工作:

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')

The simplest fix I can think of is, create a new list to store the results.我能想到的最简单的解决方法是创建一个新列表来存储结果。 That would allow you to get results ordered on a particular attribute without having to change your models or anything.这将允许您获得按特定属性排序的结果,而无需更改模型或任何东西。

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)

On your HTML page, instead of在您的 HTML 页面上,而不是

{% for post in posts %}

You can use您可以使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM