Fixed #25236 -- Deprecated {% ifequal %} and {% ifnotequal %} template tags.

The {% if %} tag provides all features of these tags.

Since Django 1.2 (May 17, 2010), the docs have hinted that
{% ifequal %} and {% ifnotequal %} will be deprecated in a future
Django version. Time to make it official.
This commit is contained in:
Jon Dufresne 2020-05-02 18:04:51 -07:00 committed by Mariusz Felisiak
parent d8cb8fdf40
commit 72a170b4c3
8 changed files with 62 additions and 9 deletions

View File

@ -8,6 +8,7 @@ from itertools import cycle as itertools_cycle, groupby
from django.conf import settings from django.conf import settings
from django.utils import timezone from django.utils import timezone
from django.utils.deprecation import RemovedInDjango40Warning
from django.utils.html import conditional_escape, format_html from django.utils.html import conditional_escape, format_html
from django.utils.lorem_ipsum import paragraphs, words from django.utils.lorem_ipsum import paragraphs, words
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -261,6 +262,7 @@ class IfChangedNode(Node):
class IfEqualNode(Node): class IfEqualNode(Node):
# RemovedInDjango40Warning.
child_nodelists = ('nodelist_true', 'nodelist_false') child_nodelists = ('nodelist_true', 'nodelist_false')
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): 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): def do_ifequal(parser, token, negate):
# RemovedInDjango40Warning.
bits = list(token.split_contents()) bits = list(token.split_contents())
if len(bits) != 3: if len(bits) != 3:
raise TemplateSyntaxError("%r takes two arguments" % bits[0]) raise TemplateSyntaxError("%r takes two arguments" % bits[0])
@ -853,6 +856,10 @@ def ifequal(parser, token):
... ...
{% endifnotequal %} {% endifnotequal %}
""" """
warnings.warn(
'The {% ifequal %} template tag is deprecated in favor of {% if %}.',
RemovedInDjango40Warning,
)
return do_ifequal(parser, token, False) 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. Output the contents of the block if the two arguments are not equal.
See ifequal. See ifequal.
""" """
warnings.warn(
'The {% ifnotequal %} template tag is deprecated in favor of '
'{% if %}.',
RemovedInDjango40Warning,
)
return do_ifequal(parser, token, True) return do_ifequal(parser, token, True)

View File

@ -90,6 +90,8 @@ details on these changes.
``django.contrib.postgres.fields.jsonb.KeyTransform``, and ``django.contrib.postgres.fields.jsonb.KeyTransform``, and
``django.contrib.postgres.fields.jsonb.KeyTextTransform`` will be removed. ``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 <deprecated-features-3.1>` for more See the :ref:`Django 3.1 release notes <deprecated-features-3.1>` for more
details on these changes. details on these changes.

View File

@ -611,10 +611,11 @@ you should use::
``ifequal`` and ``ifnotequal`` ``ifequal`` and ``ifnotequal``
------------------------------ ------------------------------
.. deprecated:: 3.1
``{% ifequal a b %} ... {% endifequal %}`` is an obsolete way to write ``{% ifequal a b %} ... {% endifequal %}`` is an obsolete way to write
``{% if a == b %} ... {% endif %}``. Likewise, ``{% ifnotequal a b %} ... ``{% if a == b %} ... {% endif %}``. Likewise, ``{% ifnotequal a b %} ...
{% endifnotequal %}`` is superseded by ``{% if a != b %} ... {% endif %}``. {% endifnotequal %}`` is superseded by ``{% if a != b %} ... {% endif %}``.
The ``ifequal`` and ``ifnotequal`` tags will be deprecated in a future release.
.. templatetag:: ifchanged .. templatetag:: ifchanged

View File

@ -812,6 +812,13 @@ Miscellaneous
* ``django.conf.urls.url()`` alias of :func:`django.urls.re_path` is * ``django.conf.urls.url()`` alias of :func:`django.urls.re_path` is
deprecated. deprecated.
* The ``{% ifequal %}`` and ``{% ifnotequal %}`` template tags are deprecated
in favor of :ttag:`{% if %}<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'
<django.template.backends.django.DjangoTemplates>` option in
:setting:`OPTIONS <TEMPLATES-OPTIONS>`.
.. _removed-features-3.1: .. _removed-features-3.1:
Features removed in 3.1 Features removed in 3.1

View File

@ -1,5 +1,6 @@
from django.template import TemplateSyntaxError 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 django.utils.safestring import mark_safe
from ..utils import SafeClass, UnsafeClass, setup from ..utils import SafeClass, UnsafeClass, setup
@ -81,6 +82,7 @@ class AutoescapeTagTests(SimpleTestCase):
with self.assertRaises(TemplateSyntaxError): with self.assertRaises(TemplateSyntaxError):
self.engine.render_to_string('autoescape-filtertag01', {'first': '<a>'}) self.engine.render_to_string('autoescape-filtertag01', {'first': '<a>'})
@ignore_warnings(category=RemovedInDjango40Warning)
@setup({'autoescape-ifequal01': '{% ifequal var "this & that" %}yes{% endifequal %}'}) @setup({'autoescape-ifequal01': '{% ifequal var "this & that" %}yes{% endifequal %}'})
def test_autoescape_ifequal01(self): def test_autoescape_ifequal01(self):
""" """

View File

@ -1,10 +1,12 @@
from django.template import TemplateSyntaxError from django.template import TemplateSyntaxError
from django.template.defaulttags import IfEqualNode 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 from ..utils import setup
@ignore_warnings(category=RemovedInDjango40Warning)
class IfEqualTagTests(SimpleTestCase): class IfEqualTagTests(SimpleTestCase):
@setup({'ifequal01': '{% ifequal a b %}yes{% endifequal %}'}) @setup({'ifequal01': '{% ifequal a b %}yes{% endifequal %}'})
@ -196,6 +198,7 @@ class IfEqualTagTests(SimpleTestCase):
self.assertEqual(output, 'x') self.assertEqual(output, 'x')
@ignore_warnings(category=RemovedInDjango40Warning)
class IfNotEqualTagTests(SimpleTestCase): class IfNotEqualTagTests(SimpleTestCase):
@setup({'ifnotequal01': '{% ifnotequal a b %}yes{% endifnotequal %}'}) @setup({'ifnotequal01': '{% ifnotequal a b %}yes{% endifnotequal %}'})
@ -224,7 +227,31 @@ class IfNotEqualTagTests(SimpleTestCase):
self.engine.render_to_string('one_var', {'a': 1}) 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): def test_repr(self):
node = IfEqualNode(var1='a', var2='b', nodelist_true=[], nodelist_false=[], negate=False) node = IfEqualNode(var1='a', var2='b', nodelist_true=[], nodelist_false=[], negate=False)
self.assertEqual(repr(node), '<IfEqualNode>') self.assertEqual(repr(node), '<IfEqualNode>')

View File

@ -75,9 +75,9 @@ class ResetCycleTagTests(SimpleTestCase):
@setup({'resetcycle10': "{% for i in test %}" @setup({'resetcycle10': "{% for i in test %}"
"{% cycle 'X' 'Y' 'Z' as XYZ %}" "{% cycle 'X' 'Y' 'Z' as XYZ %}"
"{% cycle 'a' 'b' 'c' as abc %}" "{% cycle 'a' 'b' 'c' as abc %}"
"{% ifequal i 1 %}" "{% if i == 1 %}"
"{% resetcycle abc %}" "{% resetcycle abc %}"
"{% endifequal %}" "{% endif %}"
"{% endfor %}"}) "{% endfor %}"})
def test_resetcycle10(self): def test_resetcycle10(self):
output = self.engine.render_to_string('resetcycle10', {'test': list(range(5))}) output = self.engine.render_to_string('resetcycle10', {'test': list(range(5))})
@ -86,9 +86,9 @@ class ResetCycleTagTests(SimpleTestCase):
@setup({'resetcycle11': "{% for i in test %}" @setup({'resetcycle11': "{% for i in test %}"
"{% cycle 'X' 'Y' 'Z' as XYZ %}" "{% cycle 'X' 'Y' 'Z' as XYZ %}"
"{% cycle 'a' 'b' 'c' as abc %}" "{% cycle 'a' 'b' 'c' as abc %}"
"{% ifequal i 1 %}" "{% if i == 1 %}"
"{% resetcycle XYZ %}" "{% resetcycle XYZ %}"
"{% endifequal %}" "{% endif %}"
"{% endfor %}"}) "{% endfor %}"})
def test_resetcycle11(self): def test_resetcycle11(self):
output = self.engine.render_to_string('resetcycle11', {'test': list(range(5))}) output = self.engine.render_to_string('resetcycle11', {'test': list(range(5))})

View File

@ -1,6 +1,7 @@
from django.template import Context, Engine from django.template import Context, Engine
from django.template.base import TextNode, VariableNode 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): class NodelistTest(SimpleTestCase):
@ -20,6 +21,7 @@ class NodelistTest(SimpleTestCase):
vars = template.nodelist.get_nodes_by_type(VariableNode) vars = template.nodelist.get_nodes_by_type(VariableNode)
self.assertEqual(len(vars), 1) self.assertEqual(len(vars), 1)
@ignore_warnings(category=RemovedInDjango40Warning)
def test_ifequal(self): def test_ifequal(self):
template = self.engine.from_string('{% ifequal x y %}{{ a }}{% endifequal %}') template = self.engine.from_string('{% ifequal x y %}{{ a }}{% endifequal %}')
vars = template.nodelist.get_nodes_by_type(VariableNode) vars = template.nodelist.get_nodes_by_type(VariableNode)