Custom CheckboxSelectMultiple Widget that holds state

71 views
Skip to first unread message

vcarney

unread,
Aug 10, 2010, 12:07:13 PM8/10/10
to Django users
I've got a form with a multi checkbox that contains static choices.
Using the forms.MultipleChoiceField with the CheckboxSelectMultiple
widget worked fine for display. However, when displaying an edit form,
the checkboxes did not hold state (all items were unchecked). To
handle this I created a custom widget based on CheckboxSelectMultiple
with the following:

class CustomCheckboxSelectMultiple(SelectMultiple):
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
has_id = attrs and 'id' in attrs
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<ul>']
# Normalize to strings
if (isinstance(value, basestring)):
value = value.replace('{','')
value = value.replace('}','')
value = value.replace('"','')
value = value.split(',')
str_values = set([force_unicode(v) for v in value])
for i, (option_value, option_label) in
enumerate(chain(self.choices, choices)):
# If an ID attribute was given, add a numeric index as a
suffix,
# so that the checkboxes don't all have the same ID
attribute.
if has_id:
final_attrs = dict(final_attrs, id='%s_%s' %
(attrs['id'], i))
label_for = u' for="%s"' % final_attrs['id']
else:
label_for = ''

cb = CheckboxInput(final_attrs, check_test=lambda value:
value in str_values)
option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value)
option_label =
conditional_escape(force_unicode(option_label))
output.append(u'<li><label%s>%s %s</label></li>' %
(label_for, rendered_cb, option_label))
output.append(u'</ul>')
return mark_safe(u'\n'.join(output))

def id_for_label(self, id_):
# See the comment for RadioSelect.id_for_label()
if id_:
id_ += '_0'
return id_
id_for_label = classmethod(id_for_label)

--------------------------------------------------------------------------------------
My customizations are:

if (isinstance(value, basestring)):
value = value.replace('{','')
value = value.replace('}','')
value = value.replace('"','')
value = value.split(',')

--------------------------------------------------------------------------------------
Is there a better way to do this in django?



wayne

unread,
Aug 10, 2010, 12:43:27 PM8/10/10
to Django users
Well, IMO any way that works and you feel comfortable supporting is
"okay". I can tell you what I did, but I don't know if it's any
better.

If I understand you correctly, you want to bring up the options a user
made previously and start from there instead of a blank slate. What I
did to accomplish this was to make an ajax call to the server, and
look up whatever identifiable information I had (user, form, etc.).
If it was in the database, I returned a form built from the previous
instance. If not, I returned a blank form. It brings in some
javascript (which is obviously not a part of Django, but is a common
component of web apps), but it made things quite a bit more
straightforward, IMO.

You can differentiate between the different options/fields (if
necessary) by using some guaranteed unique identifier and building
your form by hand, which you already appear to be doing.

HTH,

Wayne
Reply all
Reply to author
Forward
0 new messages