Opened 3 years ago

Closed 3 years ago

#33114 closed Cleanup/optimization (fixed)

StringAgg() should set output_field to TextField.

Reported by: Swen Kooij Owned by: ali sayyah
Component: contrib.postgres Version: 3.2
Severity: Normal Keywords:
Cc: Simon Charette Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Example:

class MyModel(models.Model):
     name = models.TextField()

list(MyModel.objects.annotate(names=StringAgg('name', ',')))

Results in the error:

django.core.exceptions.FieldError: Expression contains mixed types: TextField, CharField. You must set output_field.

There are two possible work-arounds:

  1. Derive from StringAgg and set the output_field:
class TextStringAgg(StringAgg):
    output_field = TextField()
  1. Wrap the expression in ExpressionWrapper:
ExpressionWrapper(StringAgg('name', ','), output_field=TextField())

This seems to be a regression introduced in 3.2 as part of this change: https://github.com/django/django/commit/1e38f1191de21b6e96736f58df57dfb851a28c1f

Change History (13)

comment:1 by Mariusz Felisiak, 3 years ago

Cc: Simon Charette added

This side-effect is documented, see 9369f0cebba1f65909a14dec6aa3515ec1eb2557 and #31967. Also, you can set output_field directly in the StringAgg(), e.g.

StringAgg('field', ';', output_field=TextField())

I'm not sure if there is anything specific that we could do.

comment:2 by Swen Kooij, 3 years ago

Sorry, I didn't quite grasp from that part of the release notes that this is expected.

Setting a default output_field on StringAgg would help. It would restore the original behaviour. It's a bit strange to get this error when dealing with strings. Whether it's a CharField or TextField, you still end up with a string in Python. Having to explicitly add an output_field for StringAgg seems to be just an annoyance.

comment:3 by Simon Charette, 3 years ago

This will be an issue for all expressions that accept mixed string types.

Since PostgreSQL documents that string_agg ( value text, delimiter text ) → text I guess we should default to output_field = models.TextField() to limit this annoyance.

in reply to:  3 comment:4 by Mariusz Felisiak, 3 years ago

Summary: StringAgg always fails on TextFieldStringAgg() should set output_field to TextField.
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Replying to Simon Charette:

This will be an issue for all expressions that accept mixed string types.

Since PostgreSQL documents that string_agg ( value text, delimiter text ) → text I guess we should default to output_field = models.TextField() to limit this annoyance.

OK, agreed. Swen, would you like to prepare a patch (with tests)?

comment:5 by Mariusz Felisiak, 3 years ago

Component: Database layer (models, ORM)contrib.postgres

comment:6 by ali sayyah, 3 years ago

Owner: changed from nobody to ali sayyah
Status: newassigned

comment:7 by ali sayyah, 3 years ago

Should I make the patch for 3.2 or the main branch?

comment:8 by Claude Paroz, 3 years ago

main branch (which will target 4.1, now that 4.0 is feature frozen).

in reply to:  8 comment:9 by ali sayyah, 3 years ago

Replying to Claude Paroz:

main branch (which will target 4.1, now that 4.0 is feature frozen).

Thank you.

comment:10 by ali sayyah, 3 years ago

Has patch: set

comment:11 by ali sayyah, 3 years ago

PR with the fix and a unittest: https://github.com/django/django/pull/14898

comment:12 by Simon Charette, 3 years ago

Triage Stage: AcceptedReady for checkin

comment:13 by Mariusz Felisiak <felisiak.mariusz@…>, 3 years ago

Resolution: fixed
Status: assignedclosed

In ca583783:

Fixed #33114 -- Defined default output_field of StringAgg.

Thanks Simon Charette for the review.

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