Using Django 1.11, Python 2.7, PostGres, and JSONField I'm getting behavior I don't expect.
It seems when JSONField values are initially saved/accessed in memory, they're python "integers", but when saved to the database and then re-accessed, the values are now in string format.
What about how Django handles JSONField string vs integers am I missing here? Whats the best way to get deterministic behavior here?
Am I supposed to always, say, use json.dumps to work with this stuff in string format? Should I be converting all JSONField values before trying to access any values?
Example 1 - Basic Problem
Example Model :
class ExampleModel(models.Model):
external_ids = JSONField(blank=True, null=True, default=dict)
My code:
new_example = ExampleModel.objects.create()
new_example.external_ids[1234] = {}
print(new_example.external_ids)
Output looks like this :
I can now access values stored like this :
In [140]: new_example.external_ids[1234]
Out[140]: {}
I will now then save the object to the database
However, when I go back and try to access the fields again, all integer values in the JSON have been converted into strings, and I cannot access them anymore without getting a KeyError
reload_example = ExampleModel.objects.get(id=1)
reload_example.external_ids[1234]
In [144]: reload_example.external_ids[1234]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-147-064b4b6a1511> in <module>()
----> 1 reload_example.external_ids[1234]
KeyError: 1234
By this time, the integer 1234 has been converted into a string that looks like something like the following : Why is this?
In [147]: print(reload_example.external_ids)
Out[147]: {u'1234': {}}
Therefore, at this time, I have to do this to access the fields : Whats the correct way to handle this?
In [160]: c2.external_ids[str(1234)]
Out[160]: {}
Example 2 - Non-deterministic Merge Problem -
In fact, this creates some other interesting problems for me too, where integer keys and string keys get merged together in uncertain order as well.
I create a new model - and save some key value pairs down into the JSONField:
In [164]: example2 = ExampleModel.objects.create()
In [165]: example2.external_ids
Out[165]: {}
In [166]: example2.external_ids[1234] = {'567': '890'}
In [167]: example2.save()
In [169]: example2.external_ids
Out[169]: {1234: {'567': '890'}}
Then I try to reload the model back into memory :
In [170]: reload_example2 = ExampleModel.objects.get(id=2)
In [171]: reload_example2.external_ids
Out[171]: {u'1234': {u'567': u'890'}}
Then I try to save a new set of values for key 1234:
In [172]: reload_example2.external_ids[1234] = {'890': '567'}
In [173]: reload_example2.external_ids
Out[173]: {1234: {'890': '567'}, u'1234': {u'567': u'890'}}
Now it seems like both key value pairs are loaded into memory - just the older one is tracked by a string-ified key, and the new values are tracked by an integer-based key
In [174]: reload_example2.save()
Then I save and reload the model again - it seems uncertain which values actually got saved down - whats the expectation here?
In [175]: reload_example3 = ExampleModel.objects.get(id=2)
In [176]: reload_example3.external_ids
Out[176]: {u'1234': {u'890': u'567'}}
Thanks!
Oliver