Hi,
I'm using Django 3.2 on Postgres12, and I have a model with a JSONField which contains a simple dict (actually, a Django formset :-)). I would like to update just one value in the dict. I can get this to work when the new value is a hardcoded numeric 333 (quoted, as seems to be needed) like this:
pay_items.update(inputs=JSONBSet('inputs', ['inputs-0-value'], Value("333"), True))
where JSONBSet is a Func, as indicated below. However, I'd like to actually compute the value. I've tried a variety of things, without success. Here is one attempt:
pay_items.update(inputs=JSONBSet('inputs', ['inputs-0-value'],
Cast(F('inputs__inputs-0-value'), FloatField()) + Value("3"),
True))
This fails like this:
ERROR: function jsonb_set(jsonb, unknown, double precision, boolean) does not exist at character 42
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
STATEMENT: UPDATE "paiyroll_payitem" SET "inputs" = JSONB_SET("paiyroll_payitem"."inputs", '{inputs-0-value}', (CAST(("paiyroll_payitem"."inputs" -> 'inputs-0-value') AS double precision) + '3'), true) WHERE "paiyroll_payitem"."id" IN (...))
I've tried all sorts of variants with Cast, ExpressionWrapper and so on to no avail, so I'd be grateful for any shove in the right direction!
Thanks, Shaheed
class JSONBSet(Func):
function = 'JSONB_SET'
arity = 4
output_field = CharField()
def __init__(self, field, path, value, create: bool = True):
path = Value('{{{0}}}'.format(','.join(path)))
create = Value(create)
super().__init__(field, path, value, create)