Fixed #33927 -- Fixed crash when displaying ArrayField with choices in admin.

This commit is contained in:
David Wobrock 2022-08-22 23:30:14 +02:00 committed by Carlton Gibson
parent 4488a25cc9
commit 897f38fabe
2 changed files with 46 additions and 1 deletions

View File

@ -10,6 +10,7 @@ from django.db.models.deletion import Collector
from django.forms.utils import pretty_name from django.forms.utils import pretty_name
from django.urls import NoReverseMatch, reverse from django.urls import NoReverseMatch, reverse
from django.utils import formats, timezone from django.utils import formats, timezone
from django.utils.hashable import make_hashable
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.regex_helper import _lazy_re_compile from django.utils.regex_helper import _lazy_re_compile
from django.utils.text import capfirst 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 from django.contrib.admin.templatetags.admin_list import _boolean_icon
if getattr(field, "flatchoices", None): if getattr(field, "flatchoices", None):
try:
return dict(field.flatchoices).get(value, empty_value_display) 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 # BooleanField needs special-case null-handling, so it comes before the
# general null test. # general null test.
elif isinstance(field, models.BooleanField): elif isinstance(field, models.BooleanField):

View File

@ -5,6 +5,7 @@ import unittest
import uuid import uuid
from django import forms from django import forms
from django.contrib.admin.utils import display_for_field
from django.core import checks, exceptions, serializers, validators from django.core import checks, exceptions, serializers, validators
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.core.management import call_command from django.core.management import call_command
@ -1366,3 +1367,39 @@ class TestSplitFormWidget(PostgreSQLWidgetTestCase):
), ),
False, 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)