简体   繁体   中英

Django 1.9 JSONfield stored dictionary returns unicode instead

We've just upgraded to Django 1.9 and moved things to its built-in JSONfield, which we use to store a dictionary. However, when I try to read data from it, it returns unicode of the dictionary instead.

My JSONfield is defined as:

class SmsInfo(models.Model):
    [...] 
    json = JSONField(default=dict)

Data is written to it by:

params = dict(request.POST)
SmsInfo.objects.create([...], json=params, [...])

It is later read in this way:

incoming_smsses = SmsInfo.objects.select_related('game').defer('game__serialized').filter([...])

At which point:

 print incoming_smsses[0].json.__class__

returns

<type 'unicode'> 

instead of the dict I am expecting and my code crashes because it can't look up any keys.

I've been stuck on this for quite a bit, and I can't figure out why this is going wrong. I've used literal_eval as a workaround for now, which turns the unicode back into a dict. That works for now, but I'd rather tackle this at the source!

Why is my dictionary being turned to unicode here?

I just went through upgrading from a third-party JSONField to the native postgres JSONField and found through psql that the column type is still text .

So on psql, confirm your column type:

\d+ table_name

And alter the column if it's still text:

ALTER TABLE table_name ALTER COLUMN column_name TYPE jsonb USING column_name::jsonb;

As suggested by erickw in comments, this has been filed as a bug: https://code.djangoproject.com/ticket/27675

If you happened to use django-jsonfield before, there is a conflict between them, thus as the bug above suggests, the solution is to completely delete and remake the migration files of the app which uses the jsonfield.

In that case, apparently you would like to uninstall django-jsonfield as well.

I'm using Django 1.11 and postgres 11.4.

Passing list of python dicts to JSONField worked for me:

data_python = []
for i in range(3):
    entry = {
        'field1': value1,
        'field2': 999,
        'field3': 'aaaaaaaaaa',
        'field4': 'never' 
    }
    data_python.append(entry)
MyModel.objects.create(data=data_python, name='DbEntry1')

My guess is that for dicts this should work as well

And my model is:

class MetersWithNoReadings(models.Model):
    created_datetime = models.DateTimeField(auto_now_add=True)
    updated_datetime = models.DateTimeField(auto_now=True)
    name = models.CharField(max_length=25)
    data = JSONField()

As @stelios points out, this is a bug with django-jsonfield which is not compatible with the native version.

Either:

  • uninstall django-jsonfield (if it is no longer required as a project dependency, you can check with pipdeptree ), or
  • upgrade to django-jsonfield >= 1.3.0 since the issue is now closed and the fix merged.

Seems related to DB storage here. Still this JSONField acts as a validator for proper JSON formatting.

However, you can hack around and load a dict from this returned unicode string.

Try as follow :

import json
data = json.loads(incoming_smsses[0].json)

Then you can access it as a dict IMO.

You need to use native postgres JSONField

from django.contrib.postgres import fields

class Some_class(models.Model):
    json = fields.JSONField()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM