Django ORM 聚合相关数组字段
Django ORM aggregate over related array field
我有两个模型
class Record(Model):
scorable_entry = models.ForeignKey('Entry',
null=True,
blank=True,
on_delete=models.CASCADE)
class Entry(Model):
scores = ArrayField(models.IntegerField(), null=True)
我需要根据相关 Entry
模型上 scores
的总和对 Records
进行排序。
不幸的是,这个天真的代码会抛出一个错误
records
.annotate(score_rows=Func(F('scorable_entry__scores'), function='unnest'))
.annotate(scores_sum=sum('score_rows'))
.order_by('-scores_sum')
django.db.utils.NotSupportedError: aggregate function calls cannot contain set-returning function calls
我首先使用 unnest 将数组转换为行(因为否则 sum
将不起作用)。
跳过取消嵌套不起作用,因为 sum 不对数组进行运算
django.db.utils.ProgrammingError: function sum(integer[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
使用 ORM 按相关数组的总和对元素进行排序的正确方法是什么?
Django 3.1
、Postgres 12.9
您可以创建 postgres 函数来总结 int[]
并在注释中使用它
create or replace function int_array_sum(arr int[])
returns int
language plpgsql
as
$$
declare
result integer;
begin
select sum(a) into result
from unnest(arr) a;
return result;
end;
$$;
此处查询
Record.objects
.annotate(scores_sum=Func(F('scorable_entry__scores'), function='int_array_sum'))
.order_by('-scores_sum')
所以我最终使用了迁移,包括 Eugenij 的回答中的自定义函数
ARRAY_SUM_FUNCTION = """
create or replace function int_array_sum(arr integer[])
returns int
language plpgsql
as
$$
declare
result integer;
begin
select sum(a) into result
from unnest(arr) a;
return result;
end;
$$;
"""
注意arr integer[]
参数类型。
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('records', '0003_auto_20151206_1219'),
]
operations = [
migrations.RunSQL(ARRAY_SUM_FUNCTION)
]
我有两个模型
class Record(Model):
scorable_entry = models.ForeignKey('Entry',
null=True,
blank=True,
on_delete=models.CASCADE)
class Entry(Model):
scores = ArrayField(models.IntegerField(), null=True)
我需要根据相关 Entry
模型上 scores
的总和对 Records
进行排序。
不幸的是,这个天真的代码会抛出一个错误
records
.annotate(score_rows=Func(F('scorable_entry__scores'), function='unnest'))
.annotate(scores_sum=sum('score_rows'))
.order_by('-scores_sum')
django.db.utils.NotSupportedError: aggregate function calls cannot contain set-returning function calls
我首先使用 unnest 将数组转换为行(因为否则 sum
将不起作用)。
跳过取消嵌套不起作用,因为 sum 不对数组进行运算
django.db.utils.ProgrammingError: function sum(integer[]) does not exist
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
使用 ORM 按相关数组的总和对元素进行排序的正确方法是什么?
Django 3.1
、Postgres 12.9
您可以创建 postgres 函数来总结 int[]
并在注释中使用它
create or replace function int_array_sum(arr int[])
returns int
language plpgsql
as
$$
declare
result integer;
begin
select sum(a) into result
from unnest(arr) a;
return result;
end;
$$;
此处查询
Record.objects
.annotate(scores_sum=Func(F('scorable_entry__scores'), function='int_array_sum'))
.order_by('-scores_sum')
所以我最终使用了迁移,包括 Eugenij 的回答中的自定义函数
ARRAY_SUM_FUNCTION = """
create or replace function int_array_sum(arr integer[])
returns int
language plpgsql
as
$$
declare
result integer;
begin
select sum(a) into result
from unnest(arr) a;
return result;
end;
$$;
"""
注意arr integer[]
参数类型。
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('records', '0003_auto_20151206_1219'),
]
operations = [
migrations.RunSQL(ARRAY_SUM_FUNCTION)
]