Here's a snippet to pair an arbitrary form Field type (the "target field") with a checkbox. If the checkbox is not selected, the cleaned_data value for the field will be None. If the checkbox is selected, it will return the target field's cleaned value.
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | # fields.py
from django import forms
from widgets import CheckedWidget
class CheckedField(forms.Field):
"""
Class which equips the given Field class with an additional checkbox.
>>> class TestForm1(forms.Form):
... url_field = CheckedField(forms.URLField)
...
>>> TestForm1().as_table()
u'<tr><th><label for="id_url_field_0">Url field:</label></th><td><input type="checkbox" name="url_field_0" id="id_url_field_0" /><input type="text" name="url_field_1" id="id_url_field_1" /></td></tr>'
>>> form = TestForm1({})
>>> form.is_valid()
True
>>> form.cleaned_data['url_field'] == CheckedField.UNSELECTED_VALUE
True
>>> form = TestForm1({'url_field_0' : 'on'})
>>> form.is_valid()
False
>>> form.errors
{'url_field': [u'This field is required.']}
>>> form = TestForm1({'url_field_0' : 'on', 'url_field_1' : 'bogus_url'})
>>> form.is_valid()
False
>>> form.errors
{'url_field': [u'Enter a valid URL.']}
>>> form = TestForm1({'url_field_0' : 'on', 'url_field_1' : 'http://www.real.url.com/'})
>>> form.is_valid()
True
>>> form.cleaned_data['url_field']
u'http://www.real.url.com/'
>>>
"""
# the value to use if the checbox is not selected
UNSELECTED_VALUE = None
FORM_FIELD_ARGS = ('required', 'widget', 'label', 'initial', 'help_text', 'error_messages')
def __init__(self, target, *args, **kwargs):
"""
Target can either be a Field type or an instance of one.
In the former case, all the extra arguments are passed over to the target field's constructor
"""
if isinstance(target, type):
target = target(*args, **kwargs)
self.field = target
if 'widget' in kwargs:
widget = kwargs['widget']
else:
widget = self.field.widget
kwargs['widget'] = CheckedWidget(widget)
# some keyword arguments make sense only for the "target" Field subclass,
# not for forms.Field itself
field_kwargs = dict([(kw, kwargs[kw]) for kw in kwargs if kw in self.FORM_FIELD_ARGS])
super(CheckedField, self).__init__(*args, **field_kwargs)
def clean(self, value):
try:
cb_value, field_value = value
if cb_value:
# checkbox is selected, return the field's value
return self.field.clean(field_value)
else:
# checkbox is not selected, return the default value
return self.__class__.UNSELECTED_VALUE
except forms.util.ValidationError, ve:
# we don't want to swallow ValidationErrors from the "target" field
raise ve
except TypeError, ValueError:
raise forms.util.ValidationError, u'%s is not an iterable, or there is a length mismatch' % unicode(value)
# widgets.py
from django import forms
class CheckedWidget(forms.MultiWidget):
"""
A widget which pairs another widget with a CheckboxInput widget
The target widget is given as the first argument to the constructor,
and can be either an instance or a type
"""
def __init__(self, target, attrs=None):
if isinstance(target, type):
target = target(attrs)
widgets = (forms.CheckboxInput(attrs=attrs), target)
super(CheckedWidget, self).__init__(widgets, attrs)
def decompress(self, value):
"""
If the value is None, assume the CheckboxInput was not selected
"""
if value is None:
return [False, None]
return [True, value]
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.