Opened 3 months ago

Closed 3 months ago

Last modified 3 months ago

#35642 closed Bug (invalid)

After Upgrading from Django 2.2.28 to Django 3.2.25, JSONField is returning data in string rather than dictionary/list

Reported by: Bittu Ray Owned by:
Component: contrib.postgres Version: 3.2
Severity: Normal Keywords: jsonfield, django 3.2
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

class CustomPatchedJSONFormField(JSONFormField):

    def prepare_value(self, value):
        """
        Exclude returning None in case of {}, returning None makes the field empty when loaded
        from admin instead of returning {},
        which causes an error where empty dict was expected
        """
        if value != {} and value in self.empty_values:
            return None
        elif isinstance(value, str):
            return value
        else:
            return super(CustomPatchedJSONFormField, self).prepare_value(value)


class CustomJSONField(JSONField):
    """
    Overrides
    1. `formfield` to set our custom JSON field as `form_class`
    2. `from_db_value` to return a json from `str`
    """

    def formfield(self, **kwargs):
        defaults = {"form_class": CustomPatchedJSONFormField}
        defaults.update(kwargs)
        return super(JSONField, self).formfield(**defaults)

    def from_db_value(self, value, expression, connection, context=None):
        
        if isinstance(value, str):
            try:
                return json.loads(value)
            except ValueError:
                return value

        return value

My Model

class MyModel(models.Model):
      field1 = CustomJSONField(default=list)

when I am creating an object with dictionary as input, it's working perfectly fine, but when I am creating the object input as str or json.dumps, the output is also coming in string format rather than python dictionary or list format

for example

MyModel.objects.create(field1={"key1:"value"})
a = MyModel.objects.get(id=1)
print(a.field1)
# It prints - {"key1:"value"}
# It's working fine and I am getting the output in dictionary format
# but when I try this :

MyModel.objects.create(field1='{"key1:"value"}')
a = MyModel.objects.get(id=1)
print(a.field1)

# It prints - '{"key1:"value"}'
# The value of field1 is in string format rather than dictionary format

I am using Postgres as my database and it was working fine till Django 2.2.28

Change History (2)

comment:1 by Natalia Bidart, 3 months ago

Resolution: invalid
Severity: Release blockerNormal
Status: newclosed

Hello Bittu Ray! Thank you for your ticket. Please note that Django 2.2 and Django 3.2 are no longer supported, so I'll be closing this ticket accordingly. If you can reproduce this issue in the latest Django 5.0, please reopen with detailed instructions on how to reproduce.

The release notes of each version could also help you understand your issue, specifically: https://docs.djangoproject.com/en/5.0/releases/3.1/#jsonfield-for-all-supported-database-backends and https://docs.djangoproject.com/en/5.0/releases/3.1/#deprecated-jsonfield

comment:2 by Simon Charette, 3 months ago

when I am creating the object input as str or json.dumps, the output is also coming in string format rather than python dictionary or list format

That's the crux of your issue; don't do that. JSON supports storing strings as top level members so if you want objects to be stored pass dict and not their JSON serialized form.

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