Skip to content

Commit ddbc5ff

Browse files
authored
Merge pull request #44 from nagytech/feature/optgroup
Add optgroup support (#43)
2 parents 08a9ad8 + eaa184b commit ddbc5ff

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

wtforms_sqlalchemy/fields.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Useful form fields for use with SQLAlchemy ORM.
33
"""
44
import operator
5+
from collections import defaultdict
56

67
from wtforms import widgets
78
from wtforms.fields import SelectFieldBase
@@ -48,6 +49,15 @@ class QuerySelectField(SelectFieldBase):
4849
model instance and expected to return the label text. Otherwise, the model
4950
object's `__str__` will be used.
5051
52+
53+
Specify `get_group` to allow `option` elements to be grouped into `optgroup`
54+
sections. If a string, this is the name of an attribute on the model
55+
containing the group name. If a one-argument callable, this callable will
56+
be passed the model instance and expected to return a group name. Otherwise,
57+
the `option` elements will not be grouped. Note: the result of `get_group`
58+
will be used as both the grouping key and the display label in the `select`
59+
options.
60+
5161
Specify `get_render_kw` to apply HTML attributes to each option. If a
5262
string, this is the name of an attribute on the model containing a
5363
dictionary. If a one-argument callable, this callable will be passed the
@@ -69,6 +79,7 @@ def __init__(
6979
query_factory=None,
7080
get_pk=None,
7181
get_label=None,
82+
get_group=None,
7283
get_render_kw=None,
7384
allow_blank=False,
7485
blank_text="",
@@ -93,6 +104,15 @@ def __init__(
93104
else:
94105
self.get_label = get_label
95106

107+
if get_group is None:
108+
self._has_groups = False
109+
else:
110+
self._has_groups = True
111+
if isinstance(get_group, str):
112+
self.get_group = operator.attrgetter(get_group)
113+
else:
114+
self.get_group = get_group
115+
96116
if get_render_kw is None:
97117
self.get_render_kw = lambda _: {}
98118
elif isinstance(get_render_kw, str):
@@ -133,6 +153,26 @@ def iter_choices(self):
133153
for pk, obj in self._get_object_list():
134154
yield (pk, self.get_label(obj), obj == self.data, self.get_render_kw(obj))
135155

156+
def has_groups(self):
157+
return self._has_groups
158+
159+
def iter_groups(self):
160+
if self.has_groups():
161+
groups = defaultdict(list)
162+
for pk, obj in self._get_object_list():
163+
groups[self.get_group(obj)].append((pk, obj))
164+
for group, choices in groups.items():
165+
yield (group, self._choices_generator(choices))
166+
167+
def _choices_generator(self, choices):
168+
if not choices:
169+
_choices = []
170+
else:
171+
_choices = choices
172+
173+
for pk, obj in _choices:
174+
yield (pk, self.get_label(obj), obj == self.data, self.get_render_kw(obj))
175+
136176
def process_formdata(self, valuelist):
137177
if valuelist:
138178
if self.allow_blank and valuelist[0] == "__None":

0 commit comments

Comments
 (0)