[Django] #34444: Summing through a One-to-Many relationship on the property of a JSONField fails

15 views
Skip to first unread message

Django

unread,
Mar 28, 2023, 6:36:09 PM3/28/23
to django-...@googlegroups.com
#34444: Summing through a One-to-Many relationship on the property of a JSONField
fails
-------------------------------------+-------------------------------------
Reporter: Clément | Owner: nobody
Escolano |
Type: Bug | Status: new
Component: Database | Version: 4.1
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
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:

{{{
Group.objects.annotate(total=Sum("memberships__extra__amount"))
}}}

Note that the SQL query made by Django is correct but the code still
raises the error

{{{
TypeError: the JSON object must be str, bytes or bytearray, not int
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/34444>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Mar 28, 2023, 6:51:02 PM3/28/23
to django-...@googlegroups.com
#34444: Summing through a One-to-Many relationship on the property of a JSONField
fails
-------------------------------------+-------------------------------------
Reporter: Clément Escolano | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 4.1
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by Clément Escolano:

Old description:

> 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:
>
> {{{
> Group.objects.annotate(total=Sum("memberships__extra__amount"))
> }}}
>
> Note that the SQL query made by Django is correct but the code still
> raises the error
>
> {{{
> TypeError: the JSON object must be str, bytes or bytearray, not int
> }}}

New description:

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
}}}

--

--
Ticket URL: <https://code.djangoproject.com/ticket/34444#comment:1>

Django

unread,
Mar 28, 2023, 6:56:56 PM3/28/23
to django-...@googlegroups.com
#34444: Summing through a One-to-Many relationship on the property of a JSONField
fails
-------------------------------------+-------------------------------------
Reporter: Clément Escolano | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 4.1
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Clément Escolano):

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

--
Ticket URL: <https://code.djangoproject.com/ticket/34444#comment:2>

Django

unread,
Mar 29, 2023, 2:46:17 AM3/29/23
to django-...@googlegroups.com
#34444: Summing through a One-to-Many relationship on the property of a JSONField
fails
-------------------------------------+-------------------------------------
Reporter: Clément Escolano | Owner: nobody
Type: Bug | Status: closed

Component: Database layer | Version: 4.1
(models, ORM) |
Severity: Normal | Resolution: invalid

Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* status: new => closed
* resolution: => invalid


Comment:

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

--
Ticket URL: <https://code.djangoproject.com/ticket/34444#comment:3>

Reply all
Reply to author
Forward
0 new messages