mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixed #31836 -- Dropped support for JSONField __contains and __contained_by lookups on SQLite.
The current implementation works only for basic examples without supporting nested structures and doesn't follow "the general principle that the contained object must match the containing object as to structure and data contents, possibly after discarding some non-matching array elements or object key/value pairs from the containing object".
This commit is contained in:
@@ -295,6 +295,9 @@ class BaseDatabaseFeatures:
|
||||
has_native_json_field = False
|
||||
# Does the backend use PostgreSQL-style JSON operators like '->'?
|
||||
has_json_operators = False
|
||||
# Does the backend support __contains and __contained_by lookups for
|
||||
# a JSONField?
|
||||
supports_json_field_contains = True
|
||||
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
@@ -60,6 +60,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
allows_multiple_constraints_on_same_fields = False
|
||||
supports_boolean_expr_in_select_clause = False
|
||||
supports_primitives_in_json_field = False
|
||||
supports_json_field_contains = False
|
||||
|
||||
@cached_property
|
||||
def introspected_field_types(self):
|
||||
|
||||
@@ -5,7 +5,6 @@ import datetime
|
||||
import decimal
|
||||
import functools
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import operator
|
||||
import re
|
||||
@@ -235,7 +234,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
create_deterministic_function('DEGREES', 1, none_guard(math.degrees))
|
||||
create_deterministic_function('EXP', 1, none_guard(math.exp))
|
||||
create_deterministic_function('FLOOR', 1, none_guard(math.floor))
|
||||
create_deterministic_function('JSON_CONTAINS', 2, _sqlite_json_contains)
|
||||
create_deterministic_function('LN', 1, none_guard(math.log))
|
||||
create_deterministic_function('LOG', 2, none_guard(lambda x, y: math.log(y, x)))
|
||||
create_deterministic_function('LPAD', 3, _sqlite_lpad)
|
||||
@@ -601,11 +599,3 @@ def _sqlite_lpad(text, length, fill_text):
|
||||
@none_guard
|
||||
def _sqlite_rpad(text, length, fill_text):
|
||||
return (text + fill_text * length)[:length]
|
||||
|
||||
|
||||
@none_guard
|
||||
def _sqlite_json_contains(haystack, needle):
|
||||
target, candidate = json.loads(haystack), json.loads(needle)
|
||||
if isinstance(target, dict) and isinstance(candidate, dict):
|
||||
return target.items() >= candidate.items()
|
||||
return target == candidate
|
||||
|
||||
@@ -43,6 +43,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
|
||||
supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
|
||||
order_by_nulls_first = True
|
||||
supports_json_field_contains = False
|
||||
|
||||
@cached_property
|
||||
def supports_atomic_references_rename(self):
|
||||
|
||||
@@ -140,28 +140,30 @@ class DataContains(PostgresOperatorLookup):
|
||||
postgres_operator = '@>'
|
||||
|
||||
def as_sql(self, compiler, connection):
|
||||
if not connection.features.supports_json_field_contains:
|
||||
raise NotSupportedError(
|
||||
'contains lookup is not supported on this database backend.'
|
||||
)
|
||||
lhs, lhs_params = self.process_lhs(compiler, connection)
|
||||
rhs, rhs_params = self.process_rhs(compiler, connection)
|
||||
params = tuple(lhs_params) + tuple(rhs_params)
|
||||
return 'JSON_CONTAINS(%s, %s)' % (lhs, rhs), params
|
||||
|
||||
def as_oracle(self, compiler, connection):
|
||||
raise NotSupportedError('contains lookup is not supported on Oracle.')
|
||||
|
||||
|
||||
class ContainedBy(PostgresOperatorLookup):
|
||||
lookup_name = 'contained_by'
|
||||
postgres_operator = '<@'
|
||||
|
||||
def as_sql(self, compiler, connection):
|
||||
if not connection.features.supports_json_field_contains:
|
||||
raise NotSupportedError(
|
||||
'contained_by lookup is not supported on this database backend.'
|
||||
)
|
||||
lhs, lhs_params = self.process_lhs(compiler, connection)
|
||||
rhs, rhs_params = self.process_rhs(compiler, connection)
|
||||
params = tuple(rhs_params) + tuple(lhs_params)
|
||||
return 'JSON_CONTAINS(%s, %s)' % (rhs, lhs), params
|
||||
|
||||
def as_oracle(self, compiler, connection):
|
||||
raise NotSupportedError('contained_by lookup is not supported on Oracle.')
|
||||
|
||||
|
||||
class HasKeyLookup(PostgresOperatorLookup):
|
||||
logical_operator = None
|
||||
|
||||
Reference in New Issue
Block a user