0

In my models.py, I have the following code:

from __future__ import unicode_literals
from django.db import models
from django.contrib.postgres.fields import JSONField
import json

class Table(models.Model):
    name = models.CharField(max_length=255)
    structure = JSONField(default=json.dumps('{}'))

    def __unicode__(self):
        return self.name

class Column(models.Model):
    table = models.ForeignKey(Table, related_name='columns')
    name = models.CharField(max_length=255)
    required = models.BooleanField(default=True)

    def __unicode__(self):
        return self.name + ' FROM TABLE ' + self.table.name

    def save(self, *args, **kwargs):
        if not self.pk:
            self.table.structure[self.name] = {
                'required' : self.required,
            }

As you can see from the code, when a Column is saved, if the column's required field gets added to the structure of the Table. However, when I try saving a column from the admin panel, I get the following error:

TypeError at /admin/myapp/column/add/
'unicode' object does not support item assignment

I think the problem is with the default value of my structure field. I also tried the following:

structure = JSONField(default={})
structure = JSONField(default='{}')
structure = JSONField(default=dict)

Each time, I got the same error. Any help? Thanks.

darkhorse
  • 8,192
  • 21
  • 72
  • 148

2 Answers2

5

According to the doc, if you want the default to be a dict the right definition is JSONField(default=dict). Note that you may need to clean up your existing database - what has been stored as a unicode string (with your original definition) will STILL be unserialized as a unicode string.

Not that this is very cleary documented:

If you give the field a default, ensure it’s a callable such as dict (for an empty default) or a callable that returns a dict (such as a function). Incorrectly using default={} creates a mutable default that is shared between all instances of JSONField.

so you could have saved you some trouble by reading the doc first.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • I actually did read the doc, but had a migration that set it to {} before. I didn't really figure the database clearing part. Thanks though. – darkhorse Jan 23 '17 at 14:27
-2

EDIT Just leave off the default value since it's empty. That is already the default. You could also use None as the default (see this post)

Community
  • 1
  • 1
denvaar
  • 2,174
  • 2
  • 22
  • 26
  • From the doc : "A field for storing JSON encoded data. In Python the data is represented in its Python native format: dictionaries, lists, strings, numbers, booleans and None" - so that's not the problem. – bruno desthuilliers Jan 23 '17 at 08:34
  • @brunodesthuilliers you're right -- I was mistaken for a different json field package. – denvaar Jan 23 '17 at 16:53