-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathwtforms_extended_selectfield.py
79 lines (68 loc) · 2.72 KB
/
wtforms_extended_selectfield.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
from wtforms.fields import SelectField
from wtforms.validators import ValidationError
from wtforms.widgets import HTMLString, html_params
from cgi import escape
from wtforms.widgets import Select
# very loosely based on https://gist.github.com/playpauseandstop/1590178
__all__ = ('ExtendedSelectField', 'ExtendedSelectWidget')
class ExtendedSelectWidget(Select):
"""
Add support of choices with ``optgroup`` to the ``Select`` widget.
"""
def __call__(self, field, **kwargs):
kwargs.setdefault('id', field.id)
if self.multiple:
kwargs['multiple'] = True
html = ['<select %s>' % html_params(name=field.name, **kwargs)]
for item1, item2 in field.choices:
if isinstance(item2, (list,tuple)):
group_label = item1
group_items = item2
html.append('<optgroup %s>' % html_params(label=group_label))
for inner_val, inner_label in group_items:
html.append(self.render_option(inner_val, inner_label, inner_val == field.data))
html.append('</optgroup>')
else:
val = item1
label = item2
html.append(self.render_option(val, label, val == field.data))
html.append('</select>')
return HTMLString(''.join(html))
class ExtendedSelectField(SelectField):
"""
Add support of ``optgroup`` grouping to default WTForms' ``SelectField`` class.
Here is an example of how the data is laid out.
(
('Fruits', (
('apple', 'Apple'),
('peach', 'Peach'),
('pear', 'Pear')
)),
('Vegetables', (
('cucumber', 'Cucumber'),
('potato', 'Potato'),
('tomato', 'Tomato'),
)),
('other','None Of The Above')
)
It's a little strange that the tuples are (value, label) except for groups which are (Group Label, list of tuples)
but this is actually how Django does it too https://docs.djangoproject.com/en/dev/ref/models/fields/#choices
"""
widget = ExtendedSelectWidget()
def pre_validate(self, form):
"""
Don't forget to validate also values from embedded lists.
"""
for item1,item2 in self.choices:
if isinstance(item2, (list, tuple)):
group_label = item1
group_items = item2
for val,label in group_items:
if val == self.data:
return
else:
val = item1
label = item2
if val == self.data:
return
raise ValueError(self.gettext('Not a valid choice!'))