Opened 3 years ago
Closed 3 years ago
#34444 closed Bug (invalid)
Summing through a One-to-Many relationship on the property of a JSONField fails
| Reported by: | Clément Escolano | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 4.1 |
| 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 (last modified by )
Hello,
When summing through a One-to-Many relationship on the property of a JSONField, there is the following error
TypeError: the JSON object must be str, bytes or bytearray, not int
To reproduce the error, you can create a model that is linked to another model with a JSONField:
class Group(models.Model):
name = models.TextField()
class Membership(models.Model):
group = models.ForeignKey(Group, related_name="memberships")
extra = models.JSONField()
Then create a group and a membership with an amount in the JSONField:
group = Group.objects.create(name="Test")
Membership.objects.create(group=group, extra={"amount": 5})
Finally, a request is made to sum the amount property for every group:
groups = Group.objects.annotate(total=Sum("memberships__extra__amount")).all()
groups[0].total
The SQL query is correct and returns the right information but accessing the data raises the error
TypeError: the JSON object must be str, bytes or bytearray, not int
Change History (3)
comment:1 by , 3 years ago
| Description: | modified (diff) |
|---|
comment:2 by , 3 years ago
comment:3 by , 3 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
I don't know if this is normal behaviour to require casting but I guess this is OK for me
Yes, this is normal behavior as almost anything can be stored in JSONField, so we assume it's also JSON by default.
OK, sorry for the trouble, I found a solution which is casting the annotated field to
DecimalField:groups = Group.objects.annotate(total=Cast(Sum("memberships__extra__amount"), output_field=DecimalField()).all() groups[0].totalI don't know if this is normal behaviour to require casting but I guess this is OK for me