Django 1.9 Сохраненный словарь JSONfield возвращает unicode вместо

Мы только что обновили до Django 1.9 и переместили вещи на свое встроенное JSONfield, которое мы используем для хранения словаря. Тем не менее, когда я пытаюсь читать данные из него, он возвращает unicode словаря.

My JSONfield определяется как:

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

Данные записываются на него:

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

Далее читается следующим образом:

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

В какой момент:

 print incoming_smsses[0].json.__class__

возвращает

<type 'unicode'> 

вместо dict, которого я ожидаю, и мой код падает, потому что он не может искать какие-либо ключи.

Я застрял на этом совсем немного, и я не могу понять, почему это происходит не так. Я использовал literal_eval как обходное решение, которое теперь возвращает юникод в dict. Это работает сейчас, но я бы лучше занялся этим в источнике!

Почему мой словарь включен в Юникод здесь?

Ответ 1

Я только что прошел обновление от стороннего JSONField до собственного Postgres JSONField и нашел через psql, что тип столбца все еще text.

Итак, на psql, подтвердите свой тип столбца:

\d+ table_name

И измените столбец, если он все еще текст:

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

Ответ 2

Как было предложено erickw в комментариях, это было зарегистрировано как ошибка: https://code.djangoproject.com/ticket/27675

Если раньше вы использовали django-jsonfield, между ними существует конфликт, поэтому, как показывает вышеприведенная ошибка, решение состоит в том, чтобы полностью удалить и переделать файлы миграции приложения, которое использует jsonfield.

В этом случае, по-видимому, вы также захотите удалить django-jsonfield.

Ответ 3

Я использую Django 1.11 и postgres 11.4.

Передача списка python dicts в JSONField сработала для меня:

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')

Я предполагаю, что для диктов это должно сработать

И моя модель:

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()

Ответ 4

Как указывает @stelios, это ошибка с django-jsonfield, которая не совместима с нативной версией.

Или:

  • удалить django-jsonfield (если это больше не требуется в качестве зависимости проекта, вы можете проверить с помощью pipdeptree), или
  • обновите до django-jsonfield >= 1.3.0, поскольку проблема теперь закрыта, а исправление объединено.

Ответ 5

Похоже, это связано с хранилищем БД. Тем не менее этот JSONField действует как валидатор для правильного форматирования JSON.

Однако вы можете взломать и загрузить dict из этой возвращенной строки юникода.

Попробуйте следующее:

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

Затем вы можете получить к нему доступ как ИМП. dict.

Ответ 6

Вам нужно использовать собственные postgres JSONField

from django.contrib.postgres import fields

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