From 5e4c1793b714a975400b9277a66f99efafa2d92c Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Thu, 14 Sep 2023 16:03:52 +0200 Subject: [PATCH] Refs #33308 -- Removed support for passing encoded JSON string literals to JSONField & co. Per deprecation timeline. --- django/contrib/postgres/aggregates/general.py | 33 ----------- django/db/models/fields/json.py | 31 ++-------- docs/releases/5.1.txt | 3 + docs/topics/db/queries.txt | 4 -- tests/model_fields/test_jsonfield.py | 25 --------- tests/postgres_tests/test_aggregates.py | 56 +------------------ 6 files changed, 8 insertions(+), 144 deletions(-) diff --git a/django/contrib/postgres/aggregates/general.py b/django/contrib/postgres/aggregates/general.py index c8eea1034d..5de53676f6 100644 --- a/django/contrib/postgres/aggregates/general.py +++ b/django/contrib/postgres/aggregates/general.py @@ -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" diff --git a/django/db/models/fields/json.py b/django/db/models/fields/json.py index b7cde157c4..7b9b2ae6b2 100644 --- a/django/db/models/fields/json.py +++ b/django/db/models/fields/json.py @@ -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) diff --git a/docs/releases/5.1.txt b/docs/releases/5.1.txt index 4ed51d288e..2ca8a492ca 100644 --- a/docs/releases/5.1.txt +++ b/docs/releases/5.1.txt @@ -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. diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index b975f6cdfe..3f7031c2ab 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -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 `. -.. deprecated:: 4.2 - - Passing ``Value("null")`` to express JSON ``null`` is deprecated. - .. fieldlookup:: jsonfield.key Key, index, and path transforms diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py index 4a1cc075b4..40836aece7 100644 --- a/tests/model_fields/test_jsonfield.py +++ b/tests/model_fields/test_jsonfield.py @@ -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())) diff --git a/tests/postgres_tests/test_aggregates.py b/tests/postgres_tests/test_aggregates.py index bb694dae63..386c55da25 100644 --- a/tests/postgres_tests/test_aggregates.py +++ b/tests/postgres_tests/test_aggregates.py @@ -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("")) - ), - {"aggregation": ""}, - ) - - 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('', " - "output_field=JSONField()) 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("")) - ), - - @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"]})