From 897f38fabea5e1b196f11250ff6dadfffa489840 Mon Sep 17 00:00:00 2001 From: David Wobrock Date: Mon, 22 Aug 2022 23:30:14 +0200 Subject: [PATCH] Fixed #33927 -- Fixed crash when displaying ArrayField with choices in admin. --- django/contrib/admin/utils.py | 10 +++++++- tests/postgres_tests/test_array.py | 37 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py index 6cb549fb10..b971bd528f 100644 --- a/django/contrib/admin/utils.py +++ b/django/contrib/admin/utils.py @@ -10,6 +10,7 @@ from django.db.models.deletion import Collector from django.forms.utils import pretty_name from django.urls import NoReverseMatch, reverse from django.utils import formats, timezone +from django.utils.hashable import make_hashable from django.utils.html import format_html from django.utils.regex_helper import _lazy_re_compile from django.utils.text import capfirst @@ -401,7 +402,14 @@ def display_for_field(value, field, empty_value_display): from django.contrib.admin.templatetags.admin_list import _boolean_icon if getattr(field, "flatchoices", None): - return dict(field.flatchoices).get(value, empty_value_display) + try: + return dict(field.flatchoices).get(value, empty_value_display) + except TypeError: + # Allow list-like choices. + flatchoices = make_hashable(field.flatchoices) + value = make_hashable(value) + return dict(flatchoices).get(value, empty_value_display) + # BooleanField needs special-case null-handling, so it comes before the # general null test. elif isinstance(field, models.BooleanField): diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py index 1100e8f3b0..436838dd09 100644 --- a/tests/postgres_tests/test_array.py +++ b/tests/postgres_tests/test_array.py @@ -5,6 +5,7 @@ import unittest import uuid from django import forms +from django.contrib.admin.utils import display_for_field from django.core import checks, exceptions, serializers, validators from django.core.exceptions import FieldError from django.core.management import call_command @@ -1366,3 +1367,39 @@ class TestSplitFormWidget(PostgreSQLWidgetTestCase): ), False, ) + + +class TestAdminUtils(PostgreSQLTestCase): + empty_value = "-empty-" + + def test_array_display_for_field(self): + array_field = ArrayField(models.IntegerField()) + display_value = display_for_field( + [1, 2], + array_field, + self.empty_value, + ) + self.assertEqual(display_value, "1, 2") + + def test_array_with_choices_display_for_field(self): + array_field = ArrayField( + models.IntegerField(), + choices=[ + ([1, 2, 3], "1st choice"), + ([1, 2], "2nd choice"), + ], + ) + + display_value = display_for_field( + [1, 2], + array_field, + self.empty_value, + ) + self.assertEqual(display_value, "2nd choice") + + display_value = display_for_field( + [99, 99], + array_field, + self.empty_value, + ) + self.assertEqual(display_value, self.empty_value)