Как обновить только часть json, которая хранится в базе данных со списком "json path"?
Допустим, у нас есть база данных и есть json, хранящийся как строка, которая содержит конфигурации. В приложении мы хотим обновить только определенное значение и записать обратно json в виде строки в базу данных.
В HTTP-запросе предоставляется параметр "jsonPath", который отражает путь в json-файле для перехода к объекту, который мы хотим обновить. Этот параметр предоставляется в виде списка.
Примером пути может быть что-то вроде ['input', 'keyboard', 'language'] и значение, которое мы хотим установить - 'en'
Здесь мы загружаем конфигурацию из базы данных, которая работает до сих пор:
if request.data['jsonPath']:
config = json.loads(models.Config.objects.get(name__startswith='general').value
Теперь config - это обычный объект, к которому я могу получить доступ с помощью точечной нотации, например config.input.keyboard.language, и он содержит соответствующую часть в синтаксисе json.
Я могу считать значение поля со следующим синтаксисом:
config[request.data['jsonPath'][0]][request.data['jsonPath'][1]][request.data['jsonPath'[3]]
Но количество параметров может меняться, и я хочу также записать его обратно в объект config, преобразовать его обратно в строку и записать в базу данных.
Я знаю, что это не очень приятно, но мне было бы интересно, как это можно сделать таким образом
Предположим, что у вас есть вложенный объект json, подобный этому:
mydict = {
'key1': {
'key2': {
'key3': {
'foo': 'bar'
},
},
},
}
И у вас есть список "путей", подобный этому:
path = ['key1', 'key2', 'key3']
Вы можете пройти путь следующим образом:
data = mydict
for key in path:
data = data[key]
data
в итоге будет значением последнего элемента в path
, в данном случае субдикта {'foo': 'bar'}
Вы можете использовать functools.reduce
для этого:
functools.reduce(dict.get, path, data)
from functools import reduce
data = {'key1': {'key2': {'key3': {'foo': 'bar'}}}}
path = ['key1', 'key2', 'key3']
reduce(dict.get, path, data)["foo"] = baz
Результат:
{'key1': {'key2': {'key3': {'foo': 'baz'}}}}
P.S
Если тип данных data
является чем-то другим, вы можете использовать operator.itemgetter