diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 8501330c4b8..8cc430047b9 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -8,6 +8,7 @@ from itertools import cycle as itertools_cycle, groupby from django.conf import settings from django.utils import timezone +from django.utils.deprecation import RemovedInDjango40Warning from django.utils.html import conditional_escape, format_html from django.utils.lorem_ipsum import paragraphs, words from django.utils.safestring import mark_safe @@ -261,6 +262,7 @@ class IfChangedNode(Node): class IfEqualNode(Node): + # RemovedInDjango40Warning. child_nodelists = ('nodelist_true', 'nodelist_false') def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): @@ -820,6 +822,7 @@ def do_for(parser, token): def do_ifequal(parser, token, negate): + # RemovedInDjango40Warning. bits = list(token.split_contents()) if len(bits) != 3: raise TemplateSyntaxError("%r takes two arguments" % bits[0]) @@ -853,6 +856,10 @@ def ifequal(parser, token): ... {% endifnotequal %} """ + warnings.warn( + 'The {% ifequal %} template tag is deprecated in favor of {% if %}.', + RemovedInDjango40Warning, + ) return do_ifequal(parser, token, False) @@ -862,6 +869,11 @@ def ifnotequal(parser, token): Output the contents of the block if the two arguments are not equal. See ifequal. """ + warnings.warn( + 'The {% ifnotequal %} template tag is deprecated in favor of ' + '{% if %}.', + RemovedInDjango40Warning, + ) return do_ifequal(parser, token, True) diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 183ce234080..074345ef403 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -90,6 +90,8 @@ details on these changes. ``django.contrib.postgres.fields.jsonb.KeyTransform``, and ``django.contrib.postgres.fields.jsonb.KeyTextTransform`` will be removed. +* The ``{% ifequal %}`` and ``{% ifnotequal %}`` template tags will be removed. + See the :ref:`Django 3.1 release notes ` for more details on these changes. diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index cdb214c8302..a8e8ad98f8b 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -611,10 +611,11 @@ you should use:: ``ifequal`` and ``ifnotequal`` ------------------------------ +.. deprecated:: 3.1 + ``{% ifequal a b %} ... {% endifequal %}`` is an obsolete way to write ``{% if a == b %} ... {% endif %}``. Likewise, ``{% ifnotequal a b %} ... {% endifnotequal %}`` is superseded by ``{% if a != b %} ... {% endif %}``. -The ``ifequal`` and ``ifnotequal`` tags will be deprecated in a future release. .. templatetag:: ifchanged diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index 120a326628d..35e46e5650e 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -812,6 +812,13 @@ Miscellaneous * ``django.conf.urls.url()`` alias of :func:`django.urls.re_path` is deprecated. +* The ``{% ifequal %}`` and ``{% ifnotequal %}`` template tags are deprecated + in favor of :ttag:`{% if %}`. ``{% if %}`` covers all use cases, but if + you need to continue using these tags, they can be extracted from Django to a + module and included as a built-in tag in the :class:`'builtins' + ` option in + :setting:`OPTIONS `. + .. _removed-features-3.1: Features removed in 3.1 diff --git a/tests/template_tests/syntax_tests/test_autoescape.py b/tests/template_tests/syntax_tests/test_autoescape.py index e684bc94bd7..84af2baf5f2 100644 --- a/tests/template_tests/syntax_tests/test_autoescape.py +++ b/tests/template_tests/syntax_tests/test_autoescape.py @@ -1,5 +1,6 @@ from django.template import TemplateSyntaxError -from django.test import SimpleTestCase +from django.test import SimpleTestCase, ignore_warnings +from django.utils.deprecation import RemovedInDjango40Warning from django.utils.safestring import mark_safe from ..utils import SafeClass, UnsafeClass, setup @@ -81,6 +82,7 @@ class AutoescapeTagTests(SimpleTestCase): with self.assertRaises(TemplateSyntaxError): self.engine.render_to_string('autoescape-filtertag01', {'first': ''}) + @ignore_warnings(category=RemovedInDjango40Warning) @setup({'autoescape-ifequal01': '{% ifequal var "this & that" %}yes{% endifequal %}'}) def test_autoescape_ifequal01(self): """ diff --git a/tests/template_tests/syntax_tests/test_if_equal.py b/tests/template_tests/syntax_tests/test_if_equal.py index f416b955230..29ad00de8dc 100644 --- a/tests/template_tests/syntax_tests/test_if_equal.py +++ b/tests/template_tests/syntax_tests/test_if_equal.py @@ -1,10 +1,12 @@ from django.template import TemplateSyntaxError from django.template.defaulttags import IfEqualNode -from django.test import SimpleTestCase +from django.test import SimpleTestCase, ignore_warnings +from django.utils.deprecation import RemovedInDjango40Warning from ..utils import setup +@ignore_warnings(category=RemovedInDjango40Warning) class IfEqualTagTests(SimpleTestCase): @setup({'ifequal01': '{% ifequal a b %}yes{% endifequal %}'}) @@ -196,6 +198,7 @@ class IfEqualTagTests(SimpleTestCase): self.assertEqual(output, 'x') +@ignore_warnings(category=RemovedInDjango40Warning) class IfNotEqualTagTests(SimpleTestCase): @setup({'ifnotequal01': '{% ifnotequal a b %}yes{% endifnotequal %}'}) @@ -224,7 +227,31 @@ class IfNotEqualTagTests(SimpleTestCase): self.engine.render_to_string('one_var', {'a': 1}) -class IfEqualTests(SimpleTestCase): +class DeprecationTests(SimpleTestCase): + @setup( + {'ifequal_warning': '{% ifequal a b %}yes{% endifequal %}'}, + test_once=True, + ) + def test_ifequal_warning(self): + msg = ( + 'The {% ifequal %} template tag is deprecated in favor of ' + '{% if %}.' + ) + with self.assertRaisesMessage(RemovedInDjango40Warning, msg): + self.engine.render_to_string('ifequal_warning', {'a': 1, 'b': 2}) + + @setup( + {'ifnotequal_warning': '{% ifnotequal a b %}yes{% endifnoequal %}'}, + test_once=True, + ) + def test_ifnotequal_warning(self): + msg = ( + 'The {% ifnotequal %} template tag is deprecated in favor of ' + '{% if %}.' + ) + with self.assertRaisesMessage(RemovedInDjango40Warning, msg): + self.engine.render_to_string('ifnotequal_warning', {'a': 1, 'b': 2}) + def test_repr(self): node = IfEqualNode(var1='a', var2='b', nodelist_true=[], nodelist_false=[], negate=False) self.assertEqual(repr(node), '') diff --git a/tests/template_tests/syntax_tests/test_resetcycle.py b/tests/template_tests/syntax_tests/test_resetcycle.py index 669a8498645..7c3bfc55fb3 100644 --- a/tests/template_tests/syntax_tests/test_resetcycle.py +++ b/tests/template_tests/syntax_tests/test_resetcycle.py @@ -75,9 +75,9 @@ class ResetCycleTagTests(SimpleTestCase): @setup({'resetcycle10': "{% for i in test %}" "{% cycle 'X' 'Y' 'Z' as XYZ %}" "{% cycle 'a' 'b' 'c' as abc %}" - "{% ifequal i 1 %}" + "{% if i == 1 %}" "{% resetcycle abc %}" - "{% endifequal %}" + "{% endif %}" "{% endfor %}"}) def test_resetcycle10(self): output = self.engine.render_to_string('resetcycle10', {'test': list(range(5))}) @@ -86,9 +86,9 @@ class ResetCycleTagTests(SimpleTestCase): @setup({'resetcycle11': "{% for i in test %}" "{% cycle 'X' 'Y' 'Z' as XYZ %}" "{% cycle 'a' 'b' 'c' as abc %}" - "{% ifequal i 1 %}" + "{% if i == 1 %}" "{% resetcycle XYZ %}" - "{% endifequal %}" + "{% endif %}" "{% endfor %}"}) def test_resetcycle11(self): output = self.engine.render_to_string('resetcycle11', {'test': list(range(5))}) diff --git a/tests/template_tests/test_nodelist.py b/tests/template_tests/test_nodelist.py index d3b8a5bb7ed..b0e97b88daa 100644 --- a/tests/template_tests/test_nodelist.py +++ b/tests/template_tests/test_nodelist.py @@ -1,6 +1,7 @@ from django.template import Context, Engine from django.template.base import TextNode, VariableNode -from django.test import SimpleTestCase +from django.test import SimpleTestCase, ignore_warnings +from django.utils.deprecation import RemovedInDjango40Warning class NodelistTest(SimpleTestCase): @@ -20,6 +21,7 @@ class NodelistTest(SimpleTestCase): vars = template.nodelist.get_nodes_by_type(VariableNode) self.assertEqual(len(vars), 1) + @ignore_warnings(category=RemovedInDjango40Warning) def test_ifequal(self): template = self.engine.from_string('{% ifequal x y %}{{ a }}{% endifequal %}') vars = template.nodelist.get_nodes_by_type(VariableNode)