在Django模型中将NULL视为'0'

时间:2009-02-16 11:38:30

标签: database django model

我在Django应用程序中使用以下代码:

pictures = gallery.picture_set.annotate( score=models.Sum( 'picturevote__value' ) ).order_by( '-score' )

有一张画廊表。在他们每个人都是一些图片。当用户向上或向下投票时,插入“picturevote”中的新行并连接到图片。然后我可以得到图片的总分。 现在我想按照他们的分数来订购一个画廊的图片。但是由于表连接,当没有投票时,得分值可以为NULL。然而,“NULL”得分应被视为“0”。

有什么想法吗?

编辑: 好的,这里有一些额外的解释: 问题是上面示例中的聚合将score设置为NULL。当我想显示分数时,我会使用以下内容:

score = self.picturevote_set.aggregate( models.Sum( 'value' ) )[ 'value__sum' ] or 0

然后聚合导致NULL(如果没有picturevote行)或某个值。如果为NULL,则or-expression将其转换为可显示的整数值。 但这只解决了由NULL值引起的显示问题。 当我想按照第一个代码示例中的score值对图片进行排序时,所有带有NULL的条目都放在有序结果集的末尾。首先是有正分的图片,然后有负值的图片,那么到目前为止还没有被投票或者向下投票的图片,因为它们的空格为score

我的问题是如何改变这种行为,以便订单正确。

2 个答案:

答案 0 :(得分:14)

在引入注释之前,您可能已经使用extra执行此类操作,在没有投票的情况下,我认为应返回0(如果它不适用于任何特定的数据库实现,您至少可以直接插入必要的COALESCE函数调用 - COALESCE(SUM(value), 0) - 使用此方法):

pictures = gallery.picture_set.extra(
    select={
        'score': 'SELECT SUM(value) FROM yourapp_picturevote WHERE yourapp_picturevote.picture_id = yourapp_picture.id',
    },
    order_by=['-score']
)

我看不到任何内置的方法将自己的SQL添加到新的注释内容(我还没有亲自使用过),但看起来你应该能够像这样创建一个新的注释:

from django.db.models import aggregates
from django.db.models.sql import aggregates as sql_aggregates

class SumWithDefault(aggregates.Aggregate):
    name = 'SumWithDefault'

class SQLSumWithDefault(sql_aggregates.Sum):
    sql_template = 'COALESCE(%(function)s(%(field)s), %(default)s)'

setattr(sql_aggregates, 'SumWithDefault', SQLSumWithDefault)

由于SQL聚合类的查找方式需要将新聚合monkeypatch到django.db.models.sql.aggregates,这看起来相当丑陋,但我们在这里所做的只是添加了一个新的聚合,其子类{{1 ,硬编码对Sum函数的调用,并为默认值添加占位符,必须提供作为关键字参数(至少在这个非常基本的示例实现中)。

这可以让您执行以下操作:

COALESCE

答案 1 :(得分:4)

从Django 1.8开始,有一个Coalesce数据库函数。您的查询可能如下所示:

from django.db.models.functions import Coalesce    

score = self.picturevote_set.aggregate(Coalesce(models.Sum('value'), 0))