Refs #33308 -- Removed support for passing encoded JSON string literals to JSONField & co.

Per deprecation timeline.
This commit is contained in:
Mariusz Felisiak 2023-09-14 16:03:52 +02:00
parent 69af3bea99
commit 5e4c1793b7
6 changed files with 8 additions and 144 deletions

View File

@ -1,9 +1,5 @@
import json
import warnings
from django.contrib.postgres.fields import ArrayField
from django.db.models import Aggregate, BooleanField, JSONField, TextField, Value
from django.utils.deprecation import RemovedInDjango51Warning
from .mixins import OrderableAggMixin
@ -57,35 +53,6 @@ class JSONBAgg(OrderableAggMixin, Aggregate):
allow_distinct = True
output_field = JSONField()
# RemovedInDjango51Warning: When the deprecation ends, remove __init__().
def __init__(self, *expressions, default=None, **extra):
super().__init__(*expressions, default=default, **extra)
if (
isinstance(default, Value)
and isinstance(default.value, str)
and not isinstance(default.output_field, JSONField)
):
value = default.value
try:
decoded = json.loads(value)
except json.JSONDecodeError:
warnings.warn(
"Passing a Value() with an output_field that isn't a JSONField as "
"JSONBAgg(default) is deprecated. Pass default="
f"Value({value!r}, output_field=JSONField()) instead.",
stacklevel=2,
category=RemovedInDjango51Warning,
)
self.default.output_field = self.output_field
else:
self.default = Value(decoded, self.output_field)
warnings.warn(
"Passing an encoded JSON string as JSONBAgg(default) is "
f"deprecated. Pass default={decoded!r} instead.",
stacklevel=2,
category=RemovedInDjango51Warning,
)
class StringAgg(OrderableAggMixin, Aggregate):
function = "STRING_AGG"

View File

@ -1,5 +1,4 @@
import json
import warnings
from django import forms
from django.core import checks, exceptions
@ -12,7 +11,6 @@ from django.db.models.lookups import (
PostgresOperatorLookup,
Transform,
)
from django.utils.deprecation import RemovedInDjango51Warning
from django.utils.translation import gettext_lazy as _
from . import Field
@ -101,31 +99,10 @@ class JSONField(CheckFieldDefaultMixin, Field):
def get_db_prep_value(self, value, connection, prepared=False):
if not prepared:
value = self.get_prep_value(value)
# RemovedInDjango51Warning: When the deprecation ends, replace with:
# if (
# isinstance(value, expressions.Value)
# and isinstance(value.output_field, JSONField)
# ):
# value = value.value
# elif hasattr(value, "as_sql"): ...
if isinstance(value, expressions.Value):
if isinstance(value.value, str) and not isinstance(
value.output_field, JSONField
):
try:
value = json.loads(value.value, cls=self.decoder)
except json.JSONDecodeError:
value = value.value
else:
warnings.warn(
"Providing an encoded JSON string via Value() is deprecated. "
f"Use Value({value!r}, output_field=JSONField()) instead.",
category=RemovedInDjango51Warning,
)
elif isinstance(value.output_field, JSONField):
value = value.value
else:
return value
if isinstance(value, expressions.Value) and isinstance(
value.output_field, JSONField
):
value = value.value
elif hasattr(value, "as_sql"):
return value
return connection.ops.adapt_json_value(value, self.encoder)

View File

@ -274,3 +274,6 @@ to remove usage of these features.
* The ``SimpleTestCase.assertFormsetError()`` method is removed.
* The ``TransactionTestCase.assertQuerysetEqual()`` method is removed.
* Support for passing encoded JSON string literals to ``JSONField`` and
associated lookups and expressions is removed.

View File

@ -1085,10 +1085,6 @@ Unless you are sure you wish to work with SQL ``NULL`` values, consider setting
Storing JSON scalar ``null`` does not violate :attr:`null=False
<django.db.models.Field.null>`.
.. deprecated:: 4.2
Passing ``Value("null")`` to express JSON ``null`` is deprecated.
.. fieldlookup:: jsonfield.key
Key, index, and path transforms

View File

@ -37,7 +37,6 @@ from django.db.models.fields.json import (
from django.db.models.functions import Cast
from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.test.utils import CaptureQueriesContext
from django.utils.deprecation import RemovedInDjango51Warning
from .models import CustomJSONDecoder, JSONModel, NullableJSONModel, RelatedJSONModel
@ -216,30 +215,6 @@ class TestSaveLoad(TestCase):
obj.refresh_from_db()
self.assertIsNone(obj.value)
def test_ambiguous_str_value_deprecation(self):
msg = (
"Providing an encoded JSON string via Value() is deprecated. Use Value([], "
"output_field=JSONField()) instead."
)
with self.assertWarnsMessage(RemovedInDjango51Warning, msg):
obj = NullableJSONModel.objects.create(value=Value("[]"))
obj.refresh_from_db()
self.assertEqual(obj.value, [])
@skipUnlessDBFeature("supports_primitives_in_json_field")
def test_value_str_primitives_deprecation(self):
msg = (
"Providing an encoded JSON string via Value() is deprecated. Use "
"Value(None, output_field=JSONField()) instead."
)
with self.assertWarnsMessage(RemovedInDjango51Warning, msg):
obj = NullableJSONModel.objects.create(value=Value("null"))
obj.refresh_from_db()
self.assertIsNone(obj.value)
obj = NullableJSONModel.objects.create(value=Value("invalid-json"))
obj.refresh_from_db()
self.assertEqual(obj.value, "invalid-json")
@skipUnlessDBFeature("supports_primitives_in_json_field")
def test_json_null_different_from_sql_null(self):
json_null = NullableJSONModel.objects.create(value=Value(None, JSONField()))

View File

@ -14,9 +14,8 @@ from django.db.models import (
from django.db.models.fields.json import KeyTextTransform, KeyTransform
from django.db.models.functions import Cast, Concat, Substr
from django.test import skipUnlessDBFeature
from django.test.utils import Approximate, ignore_warnings
from django.test.utils import Approximate
from django.utils import timezone
from django.utils.deprecation import RemovedInDjango51Warning
from . import PostgreSQLTestCase
from .models import AggregateTestModel, HotelReservation, Room, StatTestModel
@ -152,59 +151,6 @@ class TestGeneralAggregate(PostgreSQLTestCase):
)
self.assertEqual(values, {"aggregation": expected_result})
@ignore_warnings(category=RemovedInDjango51Warning)
def test_jsonb_agg_default_str_value(self):
AggregateTestModel.objects.all().delete()
queryset = AggregateTestModel.objects.all()
self.assertEqual(
queryset.aggregate(
aggregation=JSONBAgg("integer_field", default=Value("<empty>"))
),
{"aggregation": "<empty>"},
)
def test_jsonb_agg_default_str_value_deprecation(self):
queryset = AggregateTestModel.objects.all()
msg = (
"Passing a Value() with an output_field that isn't a JSONField as "
"JSONBAgg(default) is deprecated. Pass default=Value('<empty>', "
"output_field=JSONField()) instead."
)
with self.assertWarnsMessage(RemovedInDjango51Warning, msg):
queryset.aggregate(
aggregation=JSONBAgg("integer_field", default=Value("<empty>"))
)
with self.assertWarnsMessage(RemovedInDjango51Warning, msg):
queryset.none().aggregate(
aggregation=JSONBAgg("integer_field", default=Value("<empty>"))
),
@ignore_warnings(category=RemovedInDjango51Warning)
def test_jsonb_agg_default_encoded_json_string(self):
AggregateTestModel.objects.all().delete()
queryset = AggregateTestModel.objects.all()
self.assertEqual(
queryset.aggregate(
aggregation=JSONBAgg("integer_field", default=Value("[]"))
),
{"aggregation": []},
)
def test_jsonb_agg_default_encoded_json_string_deprecation(self):
queryset = AggregateTestModel.objects.all()
msg = (
"Passing an encoded JSON string as JSONBAgg(default) is deprecated. Pass "
"default=[] instead."
)
with self.assertWarnsMessage(RemovedInDjango51Warning, msg):
queryset.aggregate(
aggregation=JSONBAgg("integer_field", default=Value("[]"))
)
with self.assertWarnsMessage(RemovedInDjango51Warning, msg):
queryset.none().aggregate(
aggregation=JSONBAgg("integer_field", default=Value("[]"))
)
def test_array_agg_charfield(self):
values = AggregateTestModel.objects.aggregate(arrayagg=ArrayAgg("char_field"))
self.assertEqual(values, {"arrayagg": ["Foo1", "Foo2", "Foo4", "Foo3"]})