I am trying to build a complex(for me) query for one of my projects. Django version is 1.11.4 and PostgreSQL version is 9.6.
Here are the models.
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)
...
I blocked somewhere here and can't go ahead.
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])))
I have a raw query. Here it is.
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"')
You can see the result in the screenshot. I guess I am on the right way. Can anyone help me?
Thanks.
Postgres has a really nice way of making an array from a subquery:
SELECT foo.id, ARRAY(SELECT bar FROM baz WHERE foo_id = foo.id) AS bars
FROM foo
To do this within the ORM, you can define a subclass of Subquery
:
class Array(Subquery):
template = 'ARRAY(%(subquery)s)'
and use this in your queryset:
queryset = ClassificationSegment.objects.annotate(
event_list=Array(event_subquery.values('event')[:6])
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With