diff --git a/wagtail/admin/tests/test_widgets.py b/wagtail/admin/tests/test_widgets.py
index 5cc66ce96d..e5cb6749be 100644
--- a/wagtail/admin/tests/test_widgets.py
+++ b/wagtail/admin/tests/test_widgets.py
@@ -322,3 +322,37 @@ class TestFilteredSelect(TestCase):
''')
+
+ def test_optgroups(self):
+ widget = widgets.FilteredSelect(choices=[
+ (None, '----'),
+ ('Big countries', [
+ ('FR', 'France', ['EU']),
+ ('JP', 'Japan', ['AS']),
+ ('RU', 'Russia', ['AS', 'EU']),
+ ('MOON', 'The moon'),
+ ]),
+ ('Small countries', [
+ ('AZ', 'Azerbaijan', ['AS']),
+ ('LI', 'Liechtenstein', ['EU']),
+ ]),
+ ('SK', 'Slovakia', ['EU'])
+ ], filter_field='id_continent')
+
+ html = widget.render('country', 'JP')
+ self.assertHTMLEqual(html, '''
+
+ ''')
diff --git a/wagtail/admin/widgets/filtered_select.py b/wagtail/admin/widgets/filtered_select.py
index 10a77557ee..bf57726889 100644
--- a/wagtail/admin/widgets/filtered_select.py
+++ b/wagtail/admin/widgets/filtered_select.py
@@ -53,16 +53,25 @@ class FilteredSelect(forms.Select):
subgroup = []
if isinstance(option_label, (list, tuple)):
+ # this is an optgroup - we will iterate over the list in the second item of
+ # the tuple (which has been assigned to option_label)
group_name = option_value
subindex = 0
choices = option_label
else:
+ # this is a top-level choice; put it in its own group with no name
group_name = None
subindex = None
- choices = [(option_value, option_label)]
+ choices = [(option_value, option_label, filter_value)]
groups.append((group_name, subgroup, index))
- for subvalue, sublabel in choices:
+ for choice in choices:
+ try:
+ (subvalue, sublabel, filter_value) = choice
+ except ValueError:
+ (subvalue, sublabel) = choice
+ filter_value = None
+
selected = (
str(subvalue) in value
and (not has_selected or self.allow_multiple_selected)