diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py index edc5441799..b82c6a82e2 100644 --- a/django/db/models/fields/json.py +++ b/django/db/models/fields/json.py @@ -146,24 +146,7 @@ class DataContains(PostgresOperatorLookup): return 'JSON_CONTAINS(%s, %s)' % (lhs, rhs), params def as_oracle(self, compiler, connection): - if isinstance(self.rhs, KeyTransform): - return HasKey(self.lhs, self.rhs).as_oracle(compiler, connection) - lhs, lhs_params = self.process_lhs(compiler, connection) - params = tuple(lhs_params) - sql = ( - "JSON_QUERY(%s, '$%s' WITH WRAPPER) = " - "JSON_QUERY('%s', '$.value' WITH WRAPPER)" - ) - rhs = json.loads(self.rhs) - if isinstance(rhs, dict): - if not rhs: - return "DBMS_LOB.SUBSTR(%s) LIKE '{%%%%}'" % lhs, params - return ' AND '.join([ - sql % ( - lhs, '.%s' % json.dumps(key), json.dumps({'value': value}), - ) for key, value in rhs.items() - ]), params - return sql % (lhs, '', json.dumps({'value': rhs})), params + raise NotSupportedError('contains lookup is not supported on Oracle.') class ContainedBy(PostgresOperatorLookup): diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index 2afd500e54..2528144d68 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -960,6 +960,10 @@ contained in the top-level of the field. For example:: >>> Dog.objects.filter(data__contains={'breed': 'collie'}) ]> +.. admonition:: Oracle + + ``contains`` is not supported on Oracle. + .. fieldlookup:: jsonfield.contained_by ``contained_by`` diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py index 1e92b34791..7b81f3f22c 100644 --- a/tests/model_fields/test_jsonfield.py +++ b/tests/model_fields/test_jsonfield.py @@ -426,6 +426,10 @@ class TestQuerying(TestCase): [self.objs[3], self.objs[4], self.objs[6]], ) + @skipIf( + connection.vendor == 'oracle', + "Oracle doesn't support contains lookup.", + ) def test_contains(self): tests = [ ({}, self.objs[2:5] + self.objs[6:8]), @@ -441,6 +445,17 @@ class TestQuerying(TestCase): qs = NullableJSONModel.objects.filter(value__contains=value) self.assertSequenceEqual(qs, expected) + @skipUnless( + connection.vendor == 'oracle', + "Oracle doesn't support contains lookup.", + ) + def test_contains_unsupported(self): + msg = 'contains lookup is not supported on Oracle.' + with self.assertRaisesMessage(NotSupportedError, msg): + NullableJSONModel.objects.filter( + value__contains={'baz': {'a': 'b', 'c': 'd'}}, + ).get() + @skipUnlessDBFeature('supports_primitives_in_json_field') def test_contains_primitives(self): for value in self.primitives: @@ -647,12 +662,12 @@ class TestQuerying(TestCase): ('value__baz__has_key', 'c'), ('value__baz__has_keys', ['a', 'c']), ('value__baz__has_any_keys', ['a', 'x']), - ('value__contains', KeyTransform('bax', 'value')), ('value__has_key', KeyTextTransform('foo', 'value')), ) - # contained_by lookup is not supported on Oracle. + # contained_by and contains lookups are not supported on Oracle. if connection.vendor != 'oracle': tests += ( + ('value__contains', KeyTransform('bax', 'value')), ('value__baz__contained_by', {'a': 'b', 'c': 'd', 'e': 'f'}), ( 'value__contained_by',