Django 自定义注解函数

Django custom annotation function

我想使用 Django 构建一个简单的热点问题列表。我有一个 function 可以根据一些参数评估每个问题的“hotness”。

函数看起来类似于此 (full function here)

def hot(ups, downs, date):
    # Do something here..
    return hotness

我的问题模型和投票模型(相关部分)

class Question(models.Model):
    title = models.CharField(max_length=150)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

class Vote(models.Model):
    question = models.ForeignKey(Question, related_name='questions_votes')
    delta = models.IntegerField(default=0)

现在,delta attribute 不是正数就是负数。热门功能接收赞成票数和反对票数以及问题的创建日期。

我试过类似的方法,但没有用。

 questions = Question.objects.annotate(hotness=hot(question_votes.filter(delta, > 0),question_votes.filter(delta < 0), 'created_at')).order_by('hotness')

我得到的错误是:global name 'question_votes' is not defined
我明白这个错误,但我不知道这样做的正确方法。

您不能使用 python 函数进行注释。注释是在数据库级别完成的计算。 Django 只为您提供一组可以由数据库处理的基本计算 - SUM、AVERAGE、MIN、MAX 等等...对于仅从 1.8 版开始的更复杂的东西,我们有一个 API 用于更复杂的 query expressions. Before Django 1.8 the only way to achieve similar functionality was to use .extra 这意味着写普通的 SQL.

所以你基本上有两个半的选择。

上半场

如果您的 Django 版本 >= 1.8,则使用 .extra 或通过新的 API 以普通 SQL 编写您的热度计算。

第二.

在您的模型中创建热度场,该场将由 cron 作业每天计算一次(或根据您的需要更频繁)。并根据您的需要使用它(最热门列表)。

对于那些寻找更新答案(Django 2.0+)的人来说,可以根据 documentation . There is a good explanation and example here 对 Func 进行子类化以生成聚合的自定义函数 post 大约 80%在 "Extending with custom database functions" 部分。