如何从注释中将结果收集到数组中?
How to collect results into array from annotation?
是否可以从不同的 Case
指令收集结果并将它们存储在数组字段中?
几个测试实例:
banana = Fruit.objects.create(name='banana', type='tropicals', country_of_import='Africa')
orange = Fruit.objects.create(name='orange', type='citrus', country_of_import='Spain')
apple = Fruit.objects.create(name='apple', type='apples', country_of_import='Russia')
这位经理需要收集案例的所有结果。 ToArray
作为完成这项工作的可能功能。根据 docs:
有一个名称相似的函数 ArrayAgg
Returns a list of values, including nulls, concatenated into an array.
它适用于一个表达式,但不适用于多个表达式:
class CustomManager(Manager):
def get_queryset(self):
query = super().get_queryset().annotate(
additional_info=ToArray(
Case(
When(
type='tropicals',
then=Value('This fruit is tropical...')
),
output_field=CharField()
),
Case(
When(
country_of_import='Spain',
then=Value('This fruits was grown in Spain'),
),
output_field=CharField()
)
)
)
return query
最后的结果是:
banana.additional_info = ['This fruit is tropical.']
orange.additional_info = ['This fruits was grown in Spain.']
这可以用现有的函数来处理还是我需要自己写一个?
实际上,没有明显的方法来实现它。最简单的解决方案是像这样使用 CombinedExpression
class:
from django.contrib.postgres.aggregates import ArrayAgg
from django.db.models import Manager, Case, When, Value, CharField
from django.db.models.expressions import CombinedExpression
class FruitManager(Manager):
def get_queryset(self):
query = super().get_queryset()
query = query.annotate(
result=(
CombinedExpression(
ArrayAgg(Case(
When(
type='tropicals',
then=Value('This fruit is tropical...'),
),
output_field=CharField()
)),
'||'
,
ArrayAgg(Case(
When(
country_of_import='Africa',
then=Value('This fruit is citrus...'),
),
output_field=CharField(),
default=Value('default value')),
),
)
)
)
return query
那将编译成下面的SQL:
SELECT "core_fruit"."id",
(
ARRAY_AGG(CASE
WHEN "core_fruit"."type" = 'tropicals'
THEN 'This fruit is tropical...'
ELSE NULL END) ||
ARRAY_AGG(
CASE
WHEN "core_fruit"."country_of_import" = 'Africa'
THEN 'This fruit is citrus...'
ELSE 'default value' END
)
) AS "result"
FROM "core_fruit"
GROUP BY "core_fruit"."id";
但有一件事值得注意,CombinedExpression
没有记录,因为仅供内部使用。
是否可以从不同的 Case
指令收集结果并将它们存储在数组字段中?
几个测试实例:
banana = Fruit.objects.create(name='banana', type='tropicals', country_of_import='Africa')
orange = Fruit.objects.create(name='orange', type='citrus', country_of_import='Spain')
apple = Fruit.objects.create(name='apple', type='apples', country_of_import='Russia')
这位经理需要收集案例的所有结果。 ToArray
作为完成这项工作的可能功能。根据 docs:
ArrayAgg
Returns a list of values, including nulls, concatenated into an array.
它适用于一个表达式,但不适用于多个表达式:
class CustomManager(Manager):
def get_queryset(self):
query = super().get_queryset().annotate(
additional_info=ToArray(
Case(
When(
type='tropicals',
then=Value('This fruit is tropical...')
),
output_field=CharField()
),
Case(
When(
country_of_import='Spain',
then=Value('This fruits was grown in Spain'),
),
output_field=CharField()
)
)
)
return query
最后的结果是:
banana.additional_info = ['This fruit is tropical.']
orange.additional_info = ['This fruits was grown in Spain.']
这可以用现有的函数来处理还是我需要自己写一个?
实际上,没有明显的方法来实现它。最简单的解决方案是像这样使用 CombinedExpression
class:
from django.contrib.postgres.aggregates import ArrayAgg
from django.db.models import Manager, Case, When, Value, CharField
from django.db.models.expressions import CombinedExpression
class FruitManager(Manager):
def get_queryset(self):
query = super().get_queryset()
query = query.annotate(
result=(
CombinedExpression(
ArrayAgg(Case(
When(
type='tropicals',
then=Value('This fruit is tropical...'),
),
output_field=CharField()
)),
'||'
,
ArrayAgg(Case(
When(
country_of_import='Africa',
then=Value('This fruit is citrus...'),
),
output_field=CharField(),
default=Value('default value')),
),
)
)
)
return query
那将编译成下面的SQL:
SELECT "core_fruit"."id",
(
ARRAY_AGG(CASE
WHEN "core_fruit"."type" = 'tropicals'
THEN 'This fruit is tropical...'
ELSE NULL END) ||
ARRAY_AGG(
CASE
WHEN "core_fruit"."country_of_import" = 'Africa'
THEN 'This fruit is citrus...'
ELSE 'default value' END
)
) AS "result"
FROM "core_fruit"
GROUP BY "core_fruit"."id";
但有一件事值得注意,CombinedExpression
没有记录,因为仅供内部使用。