diff --git a/django/contrib/admin/templates/admin/includes/fieldset.html b/django/contrib/admin/templates/admin/includes/fieldset.html index 8207d47ec4..ba260a36ce 100644 --- a/django/contrib/admin/templates/admin/includes/fieldset.html +++ b/django/contrib/admin/templates/admin/includes/fieldset.html @@ -4,11 +4,11 @@
{{ fieldset.description|safe }}
{% endif %} {% for line in fieldset %} -
- {% if line.fields|length_is:'1' %}{{ line.errors }}{% endif %} +
+ {% if line.fields|length == 1 %}{{ line.errors }}{% endif %} {% for field in line %} - - {% if not line.fields|length_is:'1' and not field.is_readonly %}{{ field.errors }}{% endif %} + + {% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %} {% if field.is_checkbox %} {{ field.field }}{{ field.label_tag }} {% else %} diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index 46334791c6..7a5b28d159 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -2,6 +2,7 @@ import random as random_module import re import types +import warnings from decimal import ROUND_HALF_UP, Context, Decimal, InvalidOperation from functools import wraps from inspect import unwrap @@ -11,6 +12,7 @@ from urllib.parse import quote from django.utils import formats from django.utils.dateformat import format, time_format +from django.utils.deprecation import RemovedInDjango51Warning from django.utils.encoding import iri_to_uri from django.utils.html import avoid_wrapping, conditional_escape, escape, escapejs from django.utils.html import json_script as _json_script @@ -611,6 +613,11 @@ def length(value): @register.filter(is_safe=False) def length_is(value, arg): """Return a boolean of whether the value's length is the argument.""" + warnings.warn( + "The length_is template filter is deprecated in favor of the length template " + "filter and the == operator within an {% if %} tag.", + RemovedInDjango51Warning, + ) try: return len(value) == int(arg) except (ValueError, TypeError): diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 160605ddcd..43c7a0fee9 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -22,6 +22,8 @@ details on these changes. * The ``AlterIndexTogether`` migration operation will be removed. A stub operation will remain for compatibility with historical migrations. +* The ``length_is`` template filter will be removed. + .. _deprecation-removed-in-5.0: 5.0 diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index c4b83a8be8..13a8694ad6 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1906,6 +1906,8 @@ The filter returns ``0`` for an undefined variable. ``length_is`` ------------- +.. deprecated:: 4.2 + Returns ``True`` if the value's length is the argument, or ``False`` otherwise. For example:: diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt index 413e9a9471..0846f05e2c 100644 --- a/docs/releases/4.2.txt +++ b/docs/releases/4.2.txt @@ -317,3 +317,18 @@ Miscellaneous for using Python's :py:mod:`secrets` module to generate passwords. * The ``AlterIndexTogether`` migration operation is deprecated. + +* The ``length_is`` template filter is deprecated in favor of :tfilter:`length` + and the ``==`` operator within an :ttag:`{% if %}` tag. For example + + .. code-block:: html+django + + {% if value|length == 4 %}…{% endif %} + {% if value|length == 4 %}True{% else %}False{% endif %} + + instead of: + + .. code-block:: html+django + + {% if value|length_is:4 %}…{% endif %} + {{ value|length_is:4 }} diff --git a/tests/template_tests/filter_tests/test_length_is.py b/tests/template_tests/filter_tests/test_length_is.py index cbda46e5b1..5f24b2ab59 100644 --- a/tests/template_tests/filter_tests/test_length_is.py +++ b/tests/template_tests/filter_tests/test_length_is.py @@ -1,9 +1,11 @@ from django.template.defaultfilters import length_is -from django.test import SimpleTestCase +from django.test import SimpleTestCase, ignore_warnings +from django.utils.deprecation import RemovedInDjango51Warning from ..utils import setup +@ignore_warnings(category=RemovedInDjango51Warning) class LengthIsTests(SimpleTestCase): @setup({"length_is01": '{% if some_list|length_is:"4" %}Four{% endif %}'}) def test_length_is01(self): @@ -103,6 +105,7 @@ class LengthIsTests(SimpleTestCase): self.assertEqual(output, "") +@ignore_warnings(category=RemovedInDjango51Warning) class FunctionTests(SimpleTestCase): def test_empty_list(self): self.assertIs(length_is([], 0), True) @@ -111,3 +114,17 @@ class FunctionTests(SimpleTestCase): def test_string(self): self.assertIs(length_is("a", 1), True) self.assertIs(length_is("a", 10), False) + + +class DeprecationTests(SimpleTestCase): + @setup( + {"length_is_warning": "{{ string|length_is:3 }}"}, + test_once=True, + ) + def test_length_is_warning(self): + msg = ( + "The length_is template filter is deprecated in favor of the length " + "template filter and the == operator within an {% if %} tag." + ) + with self.assertRaisesMessage(RemovedInDjango51Warning, msg): + self.engine.render_to_string("length_is_warning", {"string": "good"})