#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 Clément Escolano)

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 Clément Escolano, 14 months ago

Description: modified (diff)

comment:2 by Clément Escolano, 14 months ago

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].total

I don't know if this is normal behaviour to require casting but I guess this is OK for me

comment:3 by Mariusz Felisiak, 14 months ago

Resolution: invalid
Status: newclosed

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.

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