diff --git a/django/contrib/postgres/fields/jsonb.py b/django/contrib/postgres/fields/jsonb.py index 7f76b29a13..d2e44135ba 100644 --- a/django/contrib/postgres/fields/jsonb.py +++ b/django/contrib/postgres/fields/jsonb.py @@ -11,14 +11,13 @@ __all__ = ['JSONField'] class JSONField(BuiltinJSONField): - system_check_deprecated_details = { + system_check_removed_details = { 'msg': ( - 'django.contrib.postgres.fields.JSONField is deprecated. Support ' - 'for it (except in historical migrations) will be removed in ' - 'Django 4.0.' + 'django.contrib.postgres.fields.JSONField is removed except for ' + 'support in historical migrations.' ), 'hint': 'Use django.db.models.JSONField instead.', - 'id': 'fields.W904', + 'id': 'fields.E904', } diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index e79a50b831..aae23d1d20 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -212,7 +212,9 @@ Model fields historical migrations. * **fields.W904**: ``django.contrib.postgres.fields.JSONField`` is deprecated. Support for it (except in historical migrations) will be removed in Django - 4.0. + 4.0. *This check appeared in Django 3.1 and 3.2*. +* **fields.E904**: ``django.contrib.postgres.fields.JSONField`` is removed + except for support in historical migrations. File fields ~~~~~~~~~~~ diff --git a/docs/ref/contrib/postgres/fields.txt b/docs/ref/contrib/postgres/fields.txt index eee99592b3..7754ff3d65 100644 --- a/docs/ref/contrib/postgres/fields.txt +++ b/docs/ref/contrib/postgres/fields.txt @@ -482,59 +482,6 @@ using in conjunction with lookups on >>> Dog.objects.filter(data__values__contains=['collie']) ]> -``JSONField`` -============= - -.. class:: JSONField(encoder=None, **options) - - A field for storing JSON encoded data. In Python the data is represented in - its Python native format: dictionaries, lists, strings, numbers, booleans - and ``None``. - - .. attribute:: encoder - - An optional JSON-encoding class to serialize data types not supported - by the standard JSON serializer (``datetime``, ``uuid``, etc.). For - example, you can use the - :class:`~django.core.serializers.json.DjangoJSONEncoder` class or any - other :py:class:`json.JSONEncoder` subclass. - - When the value is retrieved from the database, it will be in the format - chosen by the custom encoder (most often a string), so you'll need to - take extra steps to convert the value back to the initial data type - (:meth:`Model.from_db() ` and - :meth:`Field.from_db_value() ` - are two possible hooks for that purpose). Your deserialization may need - to account for the fact that you can't be certain of the input type. - For example, you run the risk of returning a ``datetime`` that was - actually a string that just happened to be in the same format chosen - for ``datetime``\s. - - If you give the field a :attr:`~django.db.models.Field.default`, ensure - it's a callable such as ``dict`` (for an empty default) or a callable that - returns a dict (such as a function). Incorrectly using ``default={}`` - creates a mutable default that is shared between all instances of - ``JSONField``. - -.. note:: - - PostgreSQL has two native JSON based data types: ``json`` and ``jsonb``. - The main difference between them is how they are stored and how they can be - queried. PostgreSQL's ``json`` field is stored as the original string - representation of the JSON and must be decoded on the fly when queried - based on keys. The ``jsonb`` field is stored based on the actual structure - of the JSON which allows indexing. The trade-off is a small additional cost - on writing to the ``jsonb`` field. ``JSONField`` uses ``jsonb``. - -.. deprecated:: 3.1 - - Use :class:`django.db.models.JSONField` instead. - -Querying ``JSONField`` ----------------------- - -See :ref:`querying-jsonfield` for details. - .. _range-fields: Range Fields diff --git a/docs/releases/1.11.23.txt b/docs/releases/1.11.23.txt index 04acca90f1..6a3f64d92f 100644 --- a/docs/releases/1.11.23.txt +++ b/docs/releases/1.11.23.txt @@ -41,7 +41,7 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie ==================================================================================================== :lookup:`Key and index lookups ` for -:class:`~django.contrib.postgres.fields.JSONField` and :lookup:`key lookups +``django.contrib.postgres.fields.JSONField`` and :lookup:`key lookups ` for :class:`~django.contrib.postgres.fields.HStoreField` were subject to SQL injection, using a suitably crafted dictionary, with dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``. diff --git a/docs/releases/1.11.24.txt b/docs/releases/1.11.24.txt index 578854f6e7..f46997fc4c 100644 --- a/docs/releases/1.11.24.txt +++ b/docs/releases/1.11.24.txt @@ -10,6 +10,6 @@ Bugfixes ======== * Fixed crash of ``KeyTransform()`` for - :class:`~django.contrib.postgres.fields.JSONField` and + ``django.contrib.postgres.fields.JSONField`` and :class:`~django.contrib.postgres.fields.HStoreField` when using on expressions with params (:ticket:`30672`). diff --git a/docs/releases/1.11.25.txt b/docs/releases/1.11.25.txt index 7b63b92d64..76d8936ae3 100644 --- a/docs/releases/1.11.25.txt +++ b/docs/releases/1.11.25.txt @@ -10,5 +10,5 @@ Bugfixes ======== * Fixed a crash when filtering with a ``Subquery()`` annotation of a queryset - containing :class:`~django.contrib.postgres.fields.JSONField` or + containing ``django.contrib.postgres.fields.JSONField`` or :class:`~django.contrib.postgres.fields.HStoreField` (:ticket:`30769`). diff --git a/docs/releases/1.11.26.txt b/docs/releases/1.11.26.txt index 8db2cb45b8..d3c39dcf17 100644 --- a/docs/releases/1.11.26.txt +++ b/docs/releases/1.11.26.txt @@ -11,5 +11,5 @@ Bugfixes * Fixed a crash when using a ``contains``, ``contained_by``, ``has_key``, ``has_keys``, or ``has_any_keys`` lookup on - :class:`~django.contrib.postgres.fields.JSONField`, if the right or left hand + ``django.contrib.postgres.fields.JSONField``, if the right or left hand side of an expression is a key transform (:ticket:`30826`). diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index c32203aaee..0b2250f781 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -211,7 +211,7 @@ Minor features :class:`~django.contrib.postgres.indexes.BrinIndex` classes allow creating ``GIN`` and ``BRIN`` indexes in the database. -* :class:`~django.contrib.postgres.fields.JSONField` accepts a new ``encoder`` +* ``django.contrib.postgres.fields.JSONField`` accepts a new ``encoder`` parameter to specify a custom class to encode data types not supported by the standard encoder. diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index 07a75fc005..241b9daec4 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -265,7 +265,7 @@ Minor features * Added support for the :lookup:`rangefield.contained_by` lookup for some built in fields which correspond to the range fields. -* Added :class:`~django.contrib.postgres.fields.JSONField`. +* Added ``django.contrib.postgres.fields.JSONField``. * Added :doc:`/ref/contrib/postgres/aggregates`. diff --git a/docs/releases/2.1.11.txt b/docs/releases/2.1.11.txt index ae344f35b3..e2615585c1 100644 --- a/docs/releases/2.1.11.txt +++ b/docs/releases/2.1.11.txt @@ -41,7 +41,7 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie ==================================================================================================== :lookup:`Key and index lookups ` for -:class:`~django.contrib.postgres.fields.JSONField` and :lookup:`key lookups +``django.contrib.postgres.fields.JSONField`` and :lookup:`key lookups ` for :class:`~django.contrib.postgres.fields.HStoreField` were subject to SQL injection, using a suitably crafted dictionary, with dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``. diff --git a/docs/releases/2.1.12.txt b/docs/releases/2.1.12.txt index 087ad5f59d..3efeaac64b 100644 --- a/docs/releases/2.1.12.txt +++ b/docs/releases/2.1.12.txt @@ -10,6 +10,6 @@ Bugfixes ======== * Fixed crash of ``KeyTransform()`` for - :class:`~django.contrib.postgres.fields.JSONField` and + ``django.contrib.postgres.fields.JSONField`` and :class:`~django.contrib.postgres.fields.HStoreField` when using on expressions with params (:ticket:`30672`). diff --git a/docs/releases/2.1.13.txt b/docs/releases/2.1.13.txt index 502b73c8c9..52fafc4406 100644 --- a/docs/releases/2.1.13.txt +++ b/docs/releases/2.1.13.txt @@ -10,5 +10,5 @@ Bugfixes ======== * Fixed a crash when filtering with a ``Subquery()`` annotation of a queryset - containing :class:`~django.contrib.postgres.fields.JSONField` or + containing ``django.contrib.postgres.fields.JSONField`` or :class:`~django.contrib.postgres.fields.HStoreField` (:ticket:`30769`). diff --git a/docs/releases/2.1.14.txt b/docs/releases/2.1.14.txt index 310ec56012..13923e24f1 100644 --- a/docs/releases/2.1.14.txt +++ b/docs/releases/2.1.14.txt @@ -11,5 +11,5 @@ Bugfixes * Fixed a crash when using a ``contains``, ``contained_by``, ``has_key``, ``has_keys``, or ``has_any_keys`` lookup on - :class:`~django.contrib.postgres.fields.JSONField`, if the right or left hand + ``django.contrib.postgres.fields.JSONField``, if the right or left hand side of an expression is a key transform (:ticket:`30826`). diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt index bc03a67dce..283c65ca30 100644 --- a/docs/releases/2.1.txt +++ b/docs/releases/2.1.txt @@ -373,7 +373,7 @@ Miscellaneous * Since migrations are now loaded from ``.pyc`` files, you might need to delete them if you're working in a mixed Python 2 and Python 3 environment. -* Using ``None`` as a :class:`~django.contrib.postgres.fields.JSONField` lookup +* Using ``None`` as a ``django.contrib.postgres.fields.JSONField`` lookup value now matches objects that have the specified key and a null value rather than objects that don't have the key. diff --git a/docs/releases/2.2.4.txt b/docs/releases/2.2.4.txt index 8a71fec783..15682da82a 100644 --- a/docs/releases/2.2.4.txt +++ b/docs/releases/2.2.4.txt @@ -41,7 +41,7 @@ CVE-2019-14234: SQL injection possibility in key and index lookups for ``JSONFie ==================================================================================================== :lookup:`Key and index lookups ` for -:class:`~django.contrib.postgres.fields.JSONField` and :lookup:`key lookups +``django.contrib.postgres.fields.JSONField`` and :lookup:`key lookups ` for :class:`~django.contrib.postgres.fields.HStoreField` were subject to SQL injection, using a suitably crafted dictionary, with dictionary expansion, as the ``**kwargs`` passed to ``QuerySet.filter()``. diff --git a/docs/releases/2.2.5.txt b/docs/releases/2.2.5.txt index ed6ee60d01..66fcbd6bad 100644 --- a/docs/releases/2.2.5.txt +++ b/docs/releases/2.2.5.txt @@ -14,7 +14,7 @@ Bugfixes (:ticket:`30673`). * Fixed crash of ``KeyTransform()`` for - :class:`~django.contrib.postgres.fields.JSONField` and + ``django.contrib.postgres.fields.JSONField`` and :class:`~django.contrib.postgres.fields.HStoreField` when using on expressions with params (:ticket:`30672`). diff --git a/docs/releases/2.2.6.txt b/docs/releases/2.2.6.txt index 512b3601e0..23a39b90f4 100644 --- a/docs/releases/2.2.6.txt +++ b/docs/releases/2.2.6.txt @@ -14,5 +14,5 @@ Bugfixes * Fixed a regression in Django 2.2.4 that caused a crash when filtering with a ``Subquery()`` annotation of a queryset containing - :class:`~django.contrib.postgres.fields.JSONField` or + ``django.contrib.postgres.fields.JSONField`` or :class:`~django.contrib.postgres.fields.HStoreField` (:ticket:`30769`). diff --git a/docs/releases/2.2.7.txt b/docs/releases/2.2.7.txt index 75b2816c4d..deffd62201 100644 --- a/docs/releases/2.2.7.txt +++ b/docs/releases/2.2.7.txt @@ -11,7 +11,7 @@ Bugfixes * Fixed a crash when using a ``contains``, ``contained_by``, ``has_key``, ``has_keys``, or ``has_any_keys`` lookup on - :class:`~django.contrib.postgres.fields.JSONField`, if the right or left hand + ``django.contrib.postgres.fields.JSONField``, if the right or left hand side of an expression is a key transform (:ticket:`30826`). * Prevented :option:`migrate --plan` from showing that ``RunPython`` operations diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt index d8c130db4f..f25af43549 100644 --- a/docs/releases/4.0.txt +++ b/docs/releases/4.0.txt @@ -313,3 +313,6 @@ to remove usage of these features. historical migrations. * ``django.conf.urls.url()`` is removed. + +* The ``django.contrib.postgres.fields.JSONField`` model field is removed, + except for support in historical migrations. diff --git a/tests/invalid_models_tests/test_deprecated_fields.py b/tests/invalid_models_tests/test_deprecated_fields.py index e240f20ba5..a3ee618ce4 100644 --- a/tests/invalid_models_tests/test_deprecated_fields.py +++ b/tests/invalid_models_tests/test_deprecated_fields.py @@ -1,5 +1,7 @@ +from unittest import skipUnless + from django.core import checks -from django.db import models +from django.db import connection, models from django.test import SimpleTestCase from django.test.utils import isolate_apps @@ -52,3 +54,20 @@ class DeprecatedFieldsTests(SimpleTestCase): id='fields.E903', ), ]) + + @skipUnless(connection.vendor == 'postgresql', 'PostgreSQL specific SQL') + def test_postgres_jsonfield_deprecated(self): + from django.contrib.postgres.fields import JSONField + + class PostgresJSONFieldModel(models.Model): + field = JSONField() + + self.assertEqual(PostgresJSONFieldModel.check(), [ + checks.Error( + 'django.contrib.postgres.fields.JSONField is removed except ' + 'for support in historical migrations.', + hint='Use django.db.models.JSONField instead.', + obj=PostgresJSONFieldModel._meta.get_field('field'), + id='fields.E904', + ), + ]) diff --git a/tests/postgres_tests/test_json_deprecation.py b/tests/postgres_tests/test_json_deprecation.py index 69dcce3781..7c78c6a864 100644 --- a/tests/postgres_tests/test_json_deprecation.py +++ b/tests/postgres_tests/test_json_deprecation.py @@ -1,35 +1,17 @@ try: from django.contrib.postgres import forms - from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields.jsonb import ( KeyTextTransform, KeyTransform, ) except ImportError: pass -from django.core.checks import Warning as DjangoWarning from django.utils.deprecation import RemovedInDjango40Warning from . import PostgreSQLSimpleTestCase -from .models import PostgreSQLModel class DeprecationTests(PostgreSQLSimpleTestCase): - def test_model_field_deprecation_message(self): - class PostgreSQLJSONModel(PostgreSQLModel): - field = JSONField() - - self.assertEqual(PostgreSQLJSONModel().check(), [ - DjangoWarning( - 'django.contrib.postgres.fields.JSONField is deprecated. ' - 'Support for it (except in historical migrations) will be ' - 'removed in Django 4.0.', - hint='Use django.db.models.JSONField instead.', - obj=PostgreSQLJSONModel._meta.get_field('field'), - id='fields.W904', - ), - ]) - def test_form_field_deprecation_message(self): msg = ( 'django.contrib.postgres.forms.JSONField is deprecated in favor '