如何在 Django 查询集中重新创建 reddit 排序?

How to recreate reddit sorting in django queryset?

作为一个学习项目,我认为在 Django 中创建一种 reddit 克隆会很有趣。 This is where I‘m at right now. My next step is to implement the reddit sorting. I found the algorithm here. If it helps, this is the sorting in sql.

我能够在模型中将其设置为 属性,但不会保存到数据库中,这意味着您无法对其进行排序。因此,为了对其进行排序,我一直在尝试使用 annotate() 和 aggregate() 函数在查询字符串中重新创建排序算法。但是,我还没能走多远。

所以我的问题是:如何在 Django 中重新创建 reddit 排序算法?

这是我的 views.py(的一部分),它不起作用并且在第 33 行之后丢失了很多东西,尽管用于获取分数(赞成票 - 反对票)和排序的注释函数它,确实有效:

import pytz
from pytz import timezone
from datetime import datetime, timedelta
# from math import log

from django.shortcuts import render, get_object_or_404, redirect
from django.core.urlresolvers import reverse
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.db.models import F

from .models import Link, Comment
from .forms import LinkForm, CommentForm

# the reddit sorting algorithm
# epoch = datetime(1970, 1, 1, tzinfo=pytz.utc)
#
# def get_epoch_seconds(date):
#     """Returns the number of seconds from the epoch to date."""
#     td = date - epoch
#     return td.days * 86400 + td.seconds + (float(td.microseconds) * 1000000)
#
# def reddit_sort(score, date):
#     order = log(max(abs(score), 1), 10)
#     sign = 1 if score > 0 else -1 if score < 0 else 0
#     seconds = get_epoch_seconds(date) - 1134028003
#     return round(sign * order + seconds / 45000, 7)

def links(request):
    all_links = Link.objects.annotate(
        total_score = F('upvotes') - F('downvotes'),
    ).aggregate(
        Case(When(score__lt=0, then=Value(-1)),
            When(score__gt=0, then=Value(1)),
            default=0
        ) * Func('LOG', (Max(Abs(total_score), 1) + (EPOCH(F('date')) - 1134028003) / 4500)
    ).order_by('total_score')

    paginator = Paginator(all_links, 10) #show 10 links per page
    page = request.GET.get('page')

    if request.method == 'POST':
        if request.user.is_authenticated():
            form = LinkForm(data=request.POST,auto_id=True)
            if form.is_valid():
                form.full_clean()
                form.save()
                return HttpResponseRedirect('/')
        else:
            return HttpResponseRedirect('/accounts/login/?next=/')
    else:
        form = LinkForm(auto_id=True)
        try:
            links = paginator.page(page)
        except PageNotAnInteger:
            # in case of invalid page, serve homepage, should probably add error message
            links = paginator.page(1)
        except EmtyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            links = paginator.page(paginator.num_pages)
    return render(request, 'posts/links.html', {'links': links, 'form': form})

您是否正在尝试实施 the "hot" sort(还有其他几种特定于 reddit 的类型)?

reddit 将链接(和评论)的排序值存储在排序缓存中;投票处理器然后计算新的排序值并存储它。这最终比尝试在查询中进行即时排序计算要容易得多,就像您正在做的那样。它通常也更有效,因为您每次投票只会进行一次计算,而您的方法将在每个 read.[=11 上重新计算每个 post 的排序值=]