﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
36133	Passing expression with wrongly attributed text output_field to Concat crashes on Postgres due the lack of casting	Siburg		"It seems that `output_field` for an `ExpressionWrapper` no longer works in Django 5.1 as in previous versions. Example code and test is below.
{{{

class PartnerQuerySet(models.QuerySet):

    def order_by_nick_name(self):
        qs = self.annotate(
            nick_name_for_ordering=Case(
                When(
                    nick_name='',
                    # The starting 'zzzzzzzz' is intended to ensure they
                    # will be after records with nicknames. As ugly
                    # as it is, this should work on all databases.
                    # Subtracting the pk from a large number provides a
                    # reverse ordering by pk. Let's assume we never
                    # reach 900,000 records.
                    then=Concat(
                        Value('zzzzzzzz'),
                        ExpressionWrapper(999_999 - F('pk'), output_field=models.CharField()),
                        # This is probably a bug in Django 5.1, but it no longer
                        # worked when using `CharField` as output_field for the
                        # ExpressionWrapper. Amazingly, the 2-stage casting
                        # does work.
                        # Cast(
                        #     ExpressionWrapper(999_999 - F('pk'), output_field=models.BigAutoField()),
                        #     output_field=models.CharField()
                        # ),
                    ),
                ),
                default=Lower('nick_name'),
            )
        )
        return qs.order_by('nick_name_for_ordering')


class Partner(models.Model):
    name = models.CharField(max_length=128, unique=True)
    nick_name = models.CharField(max_length=64, default='', blank=True)

    objects = PartnerQuerySet().as_manager()


class PartnerQuerySetTests(TestCase):

    def test_ordering_by_nick_name(self):
        # Given
        aaron = Partner.objects.create(name='aaron', nick_name='Zorro')
        bert = Partner.objects.create(name='bert')
        zelda = Partner.objects.create(name='Zelda', nick_name='ace')
        ernie = Partner.objects.create(name='Ernie')
        # When
        qs = Partner.objects.order_by_nick_name()
        # Then
        self.assertEqual(list(qs), [zelda, aaron, ernie, bert])
        # And
        self.assertEqual(qs[2].nick_name_for_ordering, 'zzzzzzzz999995')

}}}


I'm not especially proud of that code, but it worked in Django 4.2 and 5.0 and passed the test. It fails in 5.1. My workaround for it, wrapping the `ExpressionWrapper` itself in a `Cast` solves the problem; as in the commented out snippet above. However, I don't see why that should have become necessary.

I don't know what causes this change in behaviour. I think this ticket may be related to https://code.djangoproject.com/ticket/26650"	Bug	closed	Database layer (models, ORM)	5.1	Normal	invalid	Cast, ExpressionWrapper	Siburg	Unreviewed	0	0	0	0	0	0
