Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#34144 closed Bug (invalid)

Casting a string inside a JSONField into an integer does not work on PostgreSQL

Reported by: Clément Escolano Owned by: nobody
Component: Database layer (models, ORM) Version: 4.1
Severity: Normal Keywords: postgresql, jsonfield, cast
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 casting an integer represented as a string inside a JSONField on PostgreSQL, there is the following error:

django.db.utils.DataError: cannot cast jsonb string to type integer

It works with a SQLite database.

To reproduce the error, you can create a simple model with a JSONField:

class MyModel(models.Model):
    data = models.JSONField()

MyModel.objects.create(data={"value": "3"})

MyModel.objects.annotate(actual_value=Cast("data__value", output_field=IntegerField())).first()

The produced query is the following:

SELECT "myapp_mymodel"."id",
       "myapp_mymodel"."data",
       (("myapp_mymodel"."data" -> 'value'))::integer AS "actual_value"
FROM "myapp_mymodel"
LIMIT 1;

This stackoverflow question hints that adding an extra ">" after "->" fixes it and indeed the following query returns the correct result:

SELECT "myapp_mymodel"."id",
       "myapp_mymodel"."data",
       (("myapp_mymodel"."data" ->> 'value'))::integer AS "actual_value"
FROM "myapp_mymodel"
LIMIT 1;

Change History (3)

comment:1 by Clément Escolano, 2 years ago

Description: modified (diff)

comment:2 by Mariusz Felisiak, 2 years ago

Resolution: invalid
Status: newclosed

I don't think there is much we can do 🤔 as this is a PostgreSQL caveat. On Django 4.2+ you will be able to use the KT() expression (see docs), e.g.

Cast(KT("data__value"), output_field=IntegerField())

on Django < 4.2 you can use the KeyTextTransform() expression, e.g.

Cast(KeyTextTransform("value", "data"), output_field=IntegerField())

comment:3 by Clément Escolano, 2 years ago

Thank you for the information and the method on how to solve my problem.
It would have been great that django automatically uses this method (when using the Cast method, I expect the casting to not have issues) but I assume this is for a good reason.

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