Opened 5 years ago

Closed 5 years ago

#30658 closed Bug (duplicate)

Unexpected result using union querysets with annotated columns.

Reported by: Stefan Wehrmeyer Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I have two models:

class ModelA(models.Model):
    column_a = models.CharField(max_length=255, blank=True)
    column_b = models.CharField(max_length=255, blank=True)


class ModelB(models.Model):
    column_b = models.CharField(max_length=255, blank=True)

I want to query both at once using union, filling in a default value for column_a in ModelB:

from django.db.models import Value, CharField

ModelA.objects.create(
    column_a='a',
    column_b='b',
)
ModelB.objects.create(
    column_b='b',
)

columns = ('column_a', 'column_b')

a_qs = ModelA.objects.all().values(*columns)
b_qs = (
    ModelB.objects.all()
    .annotate(
        column_a=Value("a", output_field=CharField())
    )
    .values(*columns)
)
qs = a_qs.union(b_qs)
qs

This leads to the following unexpected output:

<QuerySet [{'column_a': 'a', 'column_b': 'b'}, {'column_a': 'b', 'column_b': 'a'}]>

Note that the second row in the result (coming from b_qs) has the values for the columns mixed up!

The SQL query is:

print(qs.query)
SELECT "example_modela"."column_a", "example_modela"."column_b" FROM "example_modela" UNION SELECT "example_modelb"."column_b", a AS "column_a" FROM "example_modelb"

I'm not sure if I'm using the ORM in a wrong way. I would consider my use case (=union+annotate) valid and would expect some kind of error if the ORM was not able to deal with it.

Change History (1)

comment:1 by Mariusz Felisiak, 5 years ago

Resolution: duplicate
Status: newclosed
Summary: Unexpected result using union on two querysets with one annotating a columnUnexpected result using union querysets with annotated columns.
Version: 2.2master

Thanks for the report, this is a duplicate of #28553. Shortly, annotated columns are forced to be in a certain position, I'm not sure if we will be able to fix this. A simple workaround in your scenario is to keep annotated columns at the end i.e. columns = ('column_b', 'column_a')

Note: See TracTickets for help on using tickets.
Back to Top