如何从注释中将结果收集到数组中?

时间:2019-11-15 12:47:38

标签: python django django-queryset django-orm

是否可以从不同的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作为完成这项工作的可能功能。根据{{​​3}},有一个具有相似名称ArrayAgg的函数:

  

返回连接到数组中的值列表,包括空值。

它仅适用于一个表达式,但不适用于多个表达式:

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.']

是否可以使用现有功能处理?还是需要自己编写?

1 个答案:

答案 0 :(得分:0)

实际上,没有明显的方法可以实现此目的。最简单的解决方案是像这样使用CombinedExpression类:

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没有记录,因为仅用于内部使用。