Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Django return postgres JSONField value as string?

Environment:

  • Django 1.10.6
  • psycopg2 2.7.1
  • PostgreSQL 9.6.2 installed via Homebrew on macOS Sierra
  • Python 3.6.0 installed via Homebrew

Example model:

from django.db import models
from django.contrib.postgres.fields import JSONField


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

When I try to create an object, everything works as expected:

from myapp.models import Foo
x = Foo()
x.data = {'key1': 'value1'}
x.save()

And querying works as expected:

Foo.objects.filter(data__key1='value1').count()
# 1

However, when I try to retrieve that data from the object, the value of the .data attribute is a string:

from myapp.models import Foo
x = Foo.objects.get(id=1)
x.data
# '{"key1": "value1"}'
type(x.data)
# str

I would expect to get back a dict here. The problem gets recursively worse when trying to save back the object

x.save()
x = Foo.objects.get(id=1)
x.data
# '"{\\"key1\\": \\"value1\\"}"'
x.save()
x = Foo.objects.get(id=1)
x.data
# '"\\"{\\\\\\"key1\\\\\\": \\\\\\"value1\\\\\\"}\\""'
like image 508
mikestef9 Avatar asked Mar 13 '17 19:03

mikestef9


2 Answers

Turns out you cannot use django-jsonfield and Django's native JSONField in the same project or will you run into the weird behavior as described in the question

https://bitbucket.org/schinckel/django-jsonfield/issues/57/cannot-use-in-the-same-project-as-djangos

like image 59
mikestef9 Avatar answered Nov 17 '22 16:11

mikestef9


For me the problem was that the database was created from a backup and the column type was set to text when it should have been either json or jsonb.

Cleaning any invalid json then altering the column type with the following:

ALTER TABLE t ALTER COLUMN j TYPE jsonb USING j::text::jsonb;

(thanks to https://stackoverflow.com/a/28076909/2362877)

like image 2
frmdstryr Avatar answered Nov 17 '22 14:11

frmdstryr