Opened 4 years ago
Closed 4 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:
- Derive from
StringAggand set theoutput_field:
class TextStringAgg(StringAgg): output_field = TextField()
- 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 , 4 years ago
| Cc: | added |
|---|
comment:2 by , 4 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.
follow-up: 4 comment:3 by , 4 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.
comment:4 by , 4 years ago
| Summary: | StringAgg always fails on TextField → StringAgg() should set output_field to TextField. |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
| Type: | Uncategorized → Cleanup/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 ) → textI guess we should default tooutput_field = models.TextField()to limit this annoyance.
OK, agreed. Swen, would you like to prepare a patch (with tests)?
comment:5 by , 4 years ago
| Component: | Database layer (models, ORM) → contrib.postgres |
|---|
comment:6 by , 4 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
follow-up: 9 comment:8 by , 4 years ago
main branch (which will target 4.1, now that 4.0 is feature frozen).
comment:9 by , 4 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 , 4 years ago
| Has patch: | set |
|---|
comment:11 by , 4 years ago
PR with the fix and a unittest: https://github.com/django/django/pull/14898
comment:12 by , 4 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
This side-effect is documented, see 9369f0cebba1f65909a14dec6aa3515ec1eb2557 and #31967. Also, you can set
output_fielddirectly in theStringAgg(), e.g.StringAgg('field', ';', output_field=TextField())I'm not sure if there is anything specific that we could do.