Search code examples
pythondjangodjango-jsonfield

Appending an item to a Django JsonField - Getting a TypeError


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.


Solution

  • 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.