Django 1.11.4 Postgresql SELECT ARRAY到django orm

时间:2017-10-06 19:17:54

标签: python django python-3.6 postgresql-9.6 django-1.11

我正在尝试为我的一个项目构建一个复杂的(对我来说)查询。 Django版本是1.11.4,PostgreSQL版本是9.6。

以下是模型。

class Event(models.Model):
    ...
    name = models.CharField(max_length=256)
    classification = models.ForeignKey("events.Classification", related_name="events", null=True, blank=True)
    ...

class Classification(models.Model):
    ...
    segment = models.ForeignKey("events.ClassificationSegment", related_name="classifications", blank=True, null=True)
    ...

class ClassificationSegment(models.Model):
    ...
    name = models.CharField(max_length=256)
    ...

我在这里阻挡了某个地方,无法继续前进。

from django.db.models import CharField, Value as V
from django.db.models.functions import Concat
from django.contrib.postgres.aggregates import ArrayAgg
from django.db.models import OuterRef, Subquery
import events.models


event_subquery = events.models.Event.objects.filter(classification__segment=OuterRef('pk')) \
.annotate(event=Concat(V('{id:'), 'id', V(', name:"'), 'name', V('"}'), output_field=CharField()))

final_list = events.models.ClassificationSegment.objects.annotate(
event_list=ArrayAgg(Subquery(event_subquery.values('event')[:6])))

我有一个原始查询。在这里。

final_events = events.models.ClassificationSegment.objects.raw('SELECT "events_classificationsegment"."id", "events_classificationsegment"."name", (SELECT ARRAY(SELECT CONCAT(\'{id:\', CONCAT(U0."id", CONCAT(\',\', \'name:"\', U0."name", \'"}\'))) AS "event" FROM "events_event" U0 INNER JOIN "events_classification" U1 ON (U0."classification_id" = U1."id") WHERE U1."segment_id" = ("events_classificationsegment"."id") LIMIT 6)) AS "event_list" FROM "events_classificationsegment"')

您可以在屏幕截图中看到结果。我想我的方式正确。任何人都可以帮助我吗?

enter image description here

感谢。

1 个答案:

答案 0 :(得分:5)

Postgres有一个非常好的方法从子查询制作数组:

SELECT foo.id, ARRAY(SELECT bar FROM baz WHERE foo_id = foo.id) AS bars
  FROM foo

要在ORM中执行此操作,您可以定义Subquery的子类:

class Array(Subquery):
    template = 'ARRAY(%(subquery)s)'

并在您的查询集中使用它:

queryset = ClassificationSegment.objects.annotate(
    event_list=Array(event_subquery.values('event')[:6])
)