Skip to content

Commit 0615601

Browse files
committed
[1.11.x] Fixed #28157 -- Fixed choice ordering in form fields with grouped and non-grouped options.
Regression in b52c730. Backport of d302e2c from master
1 parent 72a93da commit 0615601

File tree

3 files changed

+76
-37
lines changed

3 files changed

+76
-37
lines changed

django/forms/widgets.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -567,25 +567,23 @@ def options(self, name, value, attrs=None):
567567

568568
def optgroups(self, name, value, attrs=None):
569569
"""Return a list of optgroups for this widget."""
570-
default = (None, [], 0)
571-
groups = [default]
570+
groups = []
572571
has_selected = False
573572

574-
for option_value, option_label in chain(self.choices):
573+
for index, (option_value, option_label) in enumerate(chain(self.choices)):
575574
if option_value is None:
576575
option_value = ''
577576

577+
subgroup = []
578578
if isinstance(option_label, (list, tuple)):
579-
index = groups[-1][2] + 1
579+
group_name = option_value
580580
subindex = 0
581-
subgroup = []
582-
groups.append((option_value, subgroup, index))
583581
choices = option_label
584582
else:
585-
index = len(default[1])
586-
subgroup = default[1]
583+
group_name = None
587584
subindex = None
588585
choices = [(option_value, option_label)]
586+
groups.append((group_name, subgroup, index))
589587

590588
for subvalue, sublabel in choices:
591589
selected = (

docs/releases/1.11.1.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,6 @@ Bugfixes
7878

7979
* Prevented migrations from dropping database indexes from ``Meta.indexes``
8080
when changing ``Field.db_index`` to ``False`` (:ticket:`28052`).
81+
82+
* Fixed a regression in choice ordering in form fields with grouped and
83+
non-grouped options (:ticket:`28157`).

tests/forms_tests/widget_tests/test_select.py

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -283,35 +283,73 @@ def test_optgroups(self):
283283
groups = list(self.widget(choices=choices).optgroups(
284284
'name', ['vhs'], attrs={'class': 'super'},
285285
))
286-
self.assertEqual(len(groups), 3)
287-
self.assertEqual(groups[0][0], None)
288-
self.assertEqual(groups[0][2], 0)
289-
self.assertEqual(len(groups[0][1]), 1)
290-
options = groups[0][1]
291-
self.assertEqual(options[0]['name'], 'name')
292-
self.assertEqual(options[0]['value'], 'unknown')
293-
self.assertEqual(options[0]['label'], 'Unknown')
294-
self.assertEqual(options[0]['index'], '0')
295-
self.assertEqual(options[0]['selected'], False)
296-
self.assertEqual(groups[1][0], 'Audio')
297-
self.assertEqual(groups[1][2], 1)
298-
self.assertEqual(len(groups[1][1]), 2)
299-
options = groups[1][1]
300-
self.assertEqual(options[0]['name'], 'name')
301-
self.assertEqual(options[0]['value'], 'vinyl')
302-
self.assertEqual(options[0]['label'], 'Vinyl')
303-
self.assertEqual(options[0]['index'], '1_0')
304-
self.assertEqual(options[1]['index'], '1_1')
305-
self.assertEqual(groups[2][0], 'Video')
306-
self.assertEqual(groups[2][2], 2)
307-
self.assertEqual(len(groups[2][1]), 2)
308-
options = groups[2][1]
309-
self.assertEqual(options[0]['name'], 'name')
310-
self.assertEqual(options[0]['value'], 'vhs')
311-
self.assertEqual(options[0]['label'], 'VHS Tape')
312-
self.assertEqual(options[0]['index'], '2_0')
313-
self.assertEqual(options[0]['selected'], True)
314-
self.assertEqual(options[1]['index'], '2_1')
286+
audio, video, unknown = groups
287+
label, options, index = audio
288+
self.assertEqual(label, 'Audio')
289+
self.assertEqual(
290+
options,
291+
[{
292+
'value': 'vinyl',
293+
'type': 'select',
294+
'attrs': {},
295+
'index': '0_0',
296+
'label': 'Vinyl',
297+
'template_name': 'django/forms/widgets/select_option.html',
298+
'name': 'name',
299+
'selected': False,
300+
}, {
301+
'value': 'cd',
302+
'type': 'select',
303+
'attrs': {},
304+
'index': '0_1',
305+
'label': 'CD',
306+
'template_name': 'django/forms/widgets/select_option.html',
307+
'name': 'name',
308+
'selected': False,
309+
}]
310+
)
311+
self.assertEqual(index, 0)
312+
label, options, index = video
313+
self.assertEqual(label, 'Video')
314+
self.assertEqual(
315+
options,
316+
[{
317+
'value': 'vhs',
318+
'template_name': 'django/forms/widgets/select_option.html',
319+
'label': 'VHS Tape',
320+
'attrs': {'selected': True},
321+
'index': '1_0',
322+
'name': 'name',
323+
'selected': True,
324+
'type': 'select',
325+
}, {
326+
'value': 'dvd',
327+
'template_name': 'django/forms/widgets/select_option.html',
328+
'label': 'DVD',
329+
'attrs': {},
330+
'index': '1_1',
331+
'name': 'name',
332+
'selected': False,
333+
'type': 'select',
334+
}]
335+
)
336+
self.assertEqual(index, 1)
337+
label, options, index = unknown
338+
self.assertEqual(label, None)
339+
self.assertEqual(
340+
options,
341+
[{
342+
'value': 'unknown',
343+
'selected': False,
344+
'template_name': 'django/forms/widgets/select_option.html',
345+
'label': 'Unknown',
346+
'attrs': {},
347+
'index': '2',
348+
'name': 'name',
349+
'type': 'select',
350+
}]
351+
)
352+
self.assertEqual(index, 2)
315353

316354
def test_deepcopy(self):
317355
"""

0 commit comments

Comments
 (0)