Django 3.1 JSONField пытается десериализовать dict

#python #django #psycopg2

#python #django #psycopg2

Вопрос:

Я сталкиваюсь с проблемами при использовании new django.db.models.JSONField , когда кажется, что столбец возвращается из базы данных, уже десериализованной, т.Е. Уже a dict . Модель снова пытается десериализовать значение, что приводит к исключению.

 TypeError: the JSON object must be str, bytes or bytearray, not dict
 

Это исключение генерируется из json.loads вызова в from_db_value методе определения JSONField класса.

     def from_db_value(self, value, expression, connection):
        if value is None:
            return value
        try:
            return json.loads(value, cls=self.decoder)
        except json.JSONDecodeError:
            return value
 

Мы запускаем postgres, и столбец определен в базе данных как json , т.е. нет jsonb . Похоже, что у моих моделей, в которых есть столбцы, которые являются jsonb , нет этой ошибки.

Похоже, у меня нет проблемы, когда столбец в модели сохраняется как строка. Только когда столбец является dict .

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


m1 = MyModel(data=json.dumps({"key": "value"})
m1.save()
m1.refresh_from_db()

m2 = MyModel(data={"key": "value")
m2.save()
m2.refresh_from_db() # Exception thrown here
 

Я предполагаю, что в этом случае он кодируется дважды. Все, что вызывает его декодирование в a dict , декодирует его, а затем декодируется в a dict на уровне модели.

 >>> import json
>>> a = json.dumps({"key": "value"})
>>> a
'{"key": "value"}'
>>> json.dumps(a)
'"{\"key\": \"value\"}"'
 

Я даже пытался придерживаться определенного поля Postgres, и у него та же проблема. В нашей базе данных уже есть записи, которые вызвали эту проблему, и поэтому я уже не могу сохранить столбец со значением json.dumps . Я даже не думаю, что это все равно устраняет проблему.

Зависимости

 Django==3.1.3
psycopg2==2.8.6
 

Комментарии:

1. Это JSONField потому, что он обрабатывает JSON автоматически. Итак, нет необходимости загружать или сбрасывать. Если вы действительно хотите сделать это вручную, используйте текстовое поле.

2. Я это понимаю. Как я уже сказал, я не хочу в json.dumps столбец. Пожалуйста, перечитайте то, что я написал.

3. Может быть полезно: code.djangoproject.com/ticket/32135 Цитата: «Похоже, что вы используете json вместо типа данных jsonb в своей базе данных, что не поддерживается».

4. Да, я думал, что суть проблемы, по-видимому, заключается json в vs jsonb . Я не знал, что они действительно не поддерживают json . Он работал нормально, пока я не обновился до 3.1. У меня сложилось впечатление, что именно тогда была отменена своего рода подразумеваемая поддержка. Похоже, нам придется перенести этот столбец в jsonb

5. В моем случае я использовал неуправляемую таблицу Django, поэтому, когда я создавал json поле в своей базе данных, я не знал об этом ограничении. Итак, мое решение состояло в том, чтобы просто изменить на jsonb .