Django查询集中的模数运算?

13

在Django查询集中,是否已经有一种方法可以根据id % 4 == 0选择对象?

目前我找到的唯一解决方案是编写自定义转换,因为模数似乎在Postgresql中得到了支持,但我遇到了错误。

这是我的代码:

from django.db.models import Lookup, Transform
from django.db.models.fields import Field, IntegerField, AutoField

class Modulo4(Transform):
    lookup_name = 'modulo4'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return "%s %% 4" % lhs, params

AutoField.register_lookup(Modulo4)

foos = Foo.filter(id__modulo4=0)

当查询集被评估时(如使用foos.count()等方法),我遇到了一个错误:

IndexError: tuple index out of range

参考django文件。看起来是由于取模运算符导致的,因为我设法使用文档示例使自定义转换工作。

如何实现这一点?有什么想法吗?

2个回答

20

我手头没有Django 1.8来测试,但看起来你可以使用注释中的F函数来实现这个,像这样:

Foo.objects.annotate(idmod4=F('id') % 4).filter(idmod4=0)

(Django 1.7及更早版本不支持在annotate中使用F)


对于Django 1.7及更早版本,您始终可以使用.extra(),但这并不是很优雅:

Foo.objects.extra(where=["id %% %s = 0"], params=[4])

很遗憾,我正在使用Django 1.7版本 :( (应该在问题中指明) - stellasia
1
@stellasia使用了Django 1.7中唯一可用的方法更新了我的答案。 - Spc_555
似乎无法使用%d参数,但我可以在不使用该选项的情况下完成它。非常感谢! - stellasia
1
@stellasia 抱歉,应该只是 %s - Spc_555

0
def as_sql(self, compiler, connection):
    lhs, params = compiler.compile(self.lhs)
    return "%s %% 4 = 0" % lhs, params

在Django 4中,我有以下行:

return "%s %% 4 = 0" % lhs, params

应该如下所示:
return "%s %%%% 4 = 0" % lhs, params

因为 %%%% 字符串将在 as_mysql 和 db cursor 中被插值两次,所以对于 SQL 语句来说,%%%% 变成了 %,即模运算。 这种行为在大多数提供创建自定义 SQL 模板功能的 Django 类中都是相同的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接