I have a model for concert setlists, and I’m attempting to write a query that gets the songs in a given “position” (Show Opener, Show Closer, Encore Opener, etc.) for each distinct show in the filtered group.
So ideally, I’d have a resulting queryset with just the event, and an annotated field for each distinct position, and the song in that position.
So for example, I have this:
context["songs"] = (
models.Setlists.objects.order_by("event__id", "song_num")
.filter(event__tour=32)
.exclude(
position__isnull=True,
)
.values("event__id")
.annotate(
show_opener=Case(
When(
Q(position="Show Opener"),
then=Subquery(
models.Songs.objects.filter(
id=OuterRef("song"),
).values(json=JSONObject(id="id", name="name")),
),
),
),
show_closer=Case(
When(
Q(position="Show Closer"),
then=Subquery(
models.Songs.objects.filter(
id=OuterRef("song"),
).values(json=JSONObject(id="id", name="name")),
),
),
),
).exclude(show_opener__isnull=True, show_closer__isnull=True)
)
This sort of works, but it includes duplicates where one annotated value is none while the other has a song and vice versa.
{'event__id': '19801003-01', 'show_opener': {'id': 164, 'name': 'Born to Run'}, 'show_closer': None}, {'event__id': '19801003-01', 'show_opener': None, 'show_closer': {'id': 1443, 'name': 'Thunder Road'}}
Even trying to do a “group by” with .values(‘event__id’, ‘position’) results in a similar result set, but one item for each position.
My goal is to have a “flattened” result set, something like:
{'event__id': '19801003-01', 'show_opener': {'id': 164, 'name': 'Born to Run'}, 'show_closer': 'show_closer': {'id': 1443, 'name': 'Thunder Road'}}
I’m aware I can just do a “regroup” in the template, but was wondering if something like the above is possible in the ORM.
Thanks in advance