#28291 closed Bug (fixed)
ArrayField cannot contain JSONField; causes SQL error
| Reported by: | no | Owned by: | vinay karanam |
|---|---|---|---|
| Component: | contrib.postgres | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | David Hagen | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Using JSONField as the subfield of ArrayField causes an error with casting:
psycopg2.ProgrammingError: column "field" is of type jsonb[] but expression is of type text[]
LINE 1: ..."postgres_tests_jsonarraymodel" ("field") VALUES (ARRAY['{"a...
Testcase:
class JSONArrayModel(PostgreSQLModel): field = ArrayField(JSONField(default=dict)) instance = JSONArrayModel(field=[{'a': 1 }, {'b': 2}]) instance.save()
Change History (9)
follow-up: 5 comment:1 by , 8 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:2 by , 8 years ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:4 by , 8 years ago
| Cc: | added |
|---|
I did some investigation to figure out why this happens because it is kind of annoying to be unable to reuse Fields backed by JsonField in ArrayFields.
The problem comes in the call to psycopg2.extensions.cursor.execute(sql, params) in django.db.backends.utils.CursorWrapper._execute (line 85 in Django 2.0). In this example, execute is called with sql = ... VALUES (%s) ... and params = [[JsonAdaptor({"a": 1}), JsonAdaptor({"a": 1})]], where JsonAdaptor is django.contrib.postgres.fields.JsonAdaptor which is a thin wrapper around psycopg2._json.Json. Now, execute is C code in psycopg2 which expands the SQL command to ... VALUES (ARRAY['{"a": 1}', '{"b": 2}']). It gets those string representations of the JSON by calling Json.getquoted. If the field has type jsonb then the quoted string appears to be a perfectly valid value to insert into the table. However, if the field has type jsonb[], then an array of quoted strings does not appear to be a valid value to insert, which is why the error is raised. The solution is to either cast the strings to jsonb or to cast the whole array to jsonb[] like this:
... VALUES (ARRAY['{"a": 1}'::jsonb, '{"b": 2}'::jsonb]) ...
... VALUES (ARRAY['{"a": 1}', '{"b": 2}']::jsonb[]) ...
Whether the bug fundamentally lies with psycopg2 or django depends on whose duty it is to make sure the conversion to string properly casts to the right type, and I don't know that.
comment:5 by , 8 years ago
Replying to Tim Graham:
PR with a failing test.
I do not agree this ticket #29096 is a duplicate of #28291(ArrayField cannot contain JSONField; causes SQL error). I'm using PostgreSQL, and it does not result in an error for me. It works as you can clearly see from the output I posted.
My question is why the JSON object is being stringified?
Thanks... Jim
comment:6 by , 8 years ago
The test in the PR still fails with the error described here so I'm not sure why your code is working. Are you using JSONField from contrib.postgres or a third-party package?
Anyway, it's clear that JSONField with ArrayField doesn't work for one reason or another so I think we only need one ticket for that. If you find a solution for your problem that doesn't address this ticket, feel free to reopen the other one.
comment:7 by , 7 years ago
| Owner: | changed from to |
|---|
PR with a failing test.