【发布时间】:2020-09-07 07:46:07
【问题描述】:
我正在尝试编写一个 Django 注释来添加从 Django 模型中单个 CharField 中的单词生成的首字母缩写。例如:
-
The ABC Company将变为TAC -
A Company Making Everything将变为ACME
我使用的是 PostgreSQL 12.2。我从https://stackoverflow.com/a/33312435/3443946找到了以下SQL:
select name, string_agg(substr(initials, 1,1)||'.', ' ') initials
from (
select name, unnest(string_to_array(full_name,' ')) initials
from app_model
) sub group by 1;
这个 SQL 工作(或多或少),现在我正在尝试使其适应 Django。我基于https://brownbears.tistory.com/496 实现了 StringToArray(稍作修改以删除内部变量引用和可能的翻译错误):
class StringToArray(Func):
function = 'string_to_array'
output_field = ArrayField(CharField(max_length=1))
arity = 1
template = "%(function)s(%(expressions)s,'%(delimiter)s','%(null)s')"
def __init__(self, expression, delimiter=',', null=''):
super().__init__(expression, delimiter=delimiter, null=null)
Unnest 看起来很简单,如下所示:
class Unnest(Func):
function = 'unnest'
上面的两个命令我是这样实现的:
Account.objects.annotate(
unnested_strings=Unnest(
StringToArray(
F('name'), delimiter=' '
)
)
).values()
以上正确返回以下查询集(为简单起见显示为 dict):
[
{
'name': 'The ABC Company',
'unnested_strings': 'The',
...
},
{
'name': 'The ABC Company',
'unnested_strings': 'ABC',
...
},
{
'name': 'The ABC Company',
'unnested_strings': 'Company',
...
},
...
]
效果很好,所以这是我用Substr 和StringAgg 实现其余部分的尝试:
Account.objects.annotate(
initials=StringAgg(
Substr(
StringToArray(
F('name'), delimiter=' '
), 1, 1
), delimiter=''
)
).values()
当我运行上述代码时,我收到以下psycopg2 错误:
django.db.utils.NotSupportedError: aggregate function calls cannot contain set-returning function calls
LINE 1: ...T "accounts_account"."name", STRING_AGG(SUBSTRING(unnest(str...
^
HINT: You might be able to move the set-returning function into a LATERAL FROM item.
从错误消息来看,Substr 似乎不能直接作用于Unnest 结果,这就是为什么原始 SQL 在使用 Substr 之前有一个group by 子句的原因。但是,我不太清楚如何在 Django 中做到这一点。有什么建议吗?
【问题讨论】:
标签: django postgresql orm