mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	newforms: Implemented RadioSelect, with unit tests
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4072 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -5,7 +5,7 @@ HTML Widget classes | ||||
| __all__ = ( | ||||
|     'Widget', 'TextInput', 'PasswordInput', 'HiddenInput', 'FileInput', | ||||
|     'Textarea', 'CheckboxInput', | ||||
|     'Select', 'SelectMultiple', | ||||
|     'Select', 'SelectMultiple', 'RadioSelect', | ||||
| ) | ||||
|  | ||||
| from django.utils.html import escape | ||||
| @@ -35,7 +35,10 @@ class Widget(object): | ||||
|         return attrs | ||||
|  | ||||
| class Input(Widget): | ||||
|     "Base class for all <input> widgets (except type='checkbox', which is special)" | ||||
|     """ | ||||
|     Base class for all <input> widgets (except type='checkbox' and | ||||
|     type='radio', which are special). | ||||
|     """ | ||||
|     input_type = None # Subclasses must define this. | ||||
|     def render(self, name, value, attrs=None): | ||||
|         if value is None: value = '' | ||||
| @@ -102,8 +105,45 @@ class SelectMultiple(Widget): | ||||
|         output.append(u'</select>') | ||||
|         return u'\n'.join(output) | ||||
|  | ||||
| class RadioSelect(Widget): | ||||
|     pass | ||||
| class RadioInput(object): | ||||
|     "An object used by RadioFieldRenderer that represents a single <input type='radio'>." | ||||
|     def __init__(self, name, value, attrs, choice): | ||||
|         self.name, self.value = name, value | ||||
|         self.attrs = attrs or {} | ||||
|         self.choice_value, self.choice_label = choice | ||||
|  | ||||
|     def __str__(self): | ||||
|         return u'<label>%s %s</label>' % (self.tag(), self.choice_label) | ||||
|  | ||||
|     def is_checked(self): | ||||
|         return self.value == str(self.choice_value) | ||||
|  | ||||
|     def tag(self): | ||||
|         final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value) | ||||
|         if self.is_checked(): | ||||
|             final_attrs['checked'] = 'checked' | ||||
|         return u'<input%s />' % flatatt(final_attrs) | ||||
|  | ||||
| class RadioFieldRenderer(object): | ||||
|     "An object used by RadioSelect to enable customization of radio widgets." | ||||
|     def __init__(self, name, value, attrs, choices): | ||||
|         self.name, self.value, self.attrs = name, value, attrs | ||||
|         self.choices = choices | ||||
|  | ||||
|     def __iter__(self): | ||||
|         for choice in self.choices: | ||||
|             yield RadioInput(self.name, self.value, self.attrs, choice) | ||||
|  | ||||
|     def __str__(self): | ||||
|         "Outputs a <ul> for this set of radio fields." | ||||
|         return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % w for w in self]) | ||||
|  | ||||
| class RadioSelect(Select): | ||||
|     def render(self, name, value, attrs=None, choices=()): | ||||
|         "Returns a RadioFieldRenderer instance rather than a Unicode string." | ||||
|         if value is None: value = '' | ||||
|         str_value = str(value) # Normalize to string. | ||||
|         return RadioFieldRenderer(name, str_value, attrs, list(chain(self.choices, choices))) | ||||
|  | ||||
| class CheckboxSelectMultiple(Widget): | ||||
|     pass | ||||
|   | ||||
| @@ -340,6 +340,117 @@ If 'choices' is passed to both the constructor and render(), then they'll both b | ||||
| <option value="5">5</option> | ||||
| </select> | ||||
|  | ||||
| # RadioSelect Widget ########################################################## | ||||
|  | ||||
| >>> w = RadioSelect() | ||||
| >>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) | ||||
| <ul> | ||||
| <li><label><input checked="checked" type="radio" name="beatle" value="J" /> John</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="P" /> Paul</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="G" /> George</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li> | ||||
| </ul> | ||||
|  | ||||
| If the value is None, none of the options are checked: | ||||
| >>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="beatle" value="J" /> John</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="P" /> Paul</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="G" /> George</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li> | ||||
| </ul> | ||||
|  | ||||
| If the value corresponds to a label (but not to an option value), none of the options are checked: | ||||
| >>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="beatle" value="J" /> John</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="P" /> Paul</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="G" /> George</label></li> | ||||
| <li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li> | ||||
| </ul> | ||||
|  | ||||
| The value is compared to its str(): | ||||
| >>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="num" value="1" /> 1</label></li> | ||||
| <li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li> | ||||
| <li><label><input type="radio" name="num" value="3" /> 3</label></li> | ||||
| </ul> | ||||
| >>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="num" value="1" /> 1</label></li> | ||||
| <li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li> | ||||
| <li><label><input type="radio" name="num" value="3" /> 3</label></li> | ||||
| </ul> | ||||
| >>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="num" value="1" /> 1</label></li> | ||||
| <li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li> | ||||
| <li><label><input type="radio" name="num" value="3" /> 3</label></li> | ||||
| </ul> | ||||
|  | ||||
| The 'choices' argument can be any iterable: | ||||
| >>> def get_choices(): | ||||
| ...     for i in range(5): | ||||
| ...         yield (i, i) | ||||
| >>> print w.render('num', 2, choices=get_choices()) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="num" value="0" /> 0</label></li> | ||||
| <li><label><input type="radio" name="num" value="1" /> 1</label></li> | ||||
| <li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li> | ||||
| <li><label><input type="radio" name="num" value="3" /> 3</label></li> | ||||
| <li><label><input type="radio" name="num" value="4" /> 4</label></li> | ||||
| </ul> | ||||
|  | ||||
| You can also pass 'choices' to the constructor: | ||||
| >>> w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)]) | ||||
| >>> print w.render('num', 2) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="num" value="1" /> 1</label></li> | ||||
| <li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li> | ||||
| <li><label><input type="radio" name="num" value="3" /> 3</label></li> | ||||
| </ul> | ||||
|  | ||||
| If 'choices' is passed to both the constructor and render(), then they'll both be in the output: | ||||
| >>> print w.render('num', 2, choices=[(4, 4), (5, 5)]) | ||||
| <ul> | ||||
| <li><label><input type="radio" name="num" value="1" /> 1</label></li> | ||||
| <li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li> | ||||
| <li><label><input type="radio" name="num" value="3" /> 3</label></li> | ||||
| <li><label><input type="radio" name="num" value="4" /> 4</label></li> | ||||
| <li><label><input type="radio" name="num" value="5" /> 5</label></li> | ||||
| </ul> | ||||
|  | ||||
| The render() method returns a RadioFieldRenderer object, whose str() is a <ul>. | ||||
| You can manipulate that object directly to customize the way the RadioSelect | ||||
| is rendered. | ||||
| >>> w = RadioSelect() | ||||
| >>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) | ||||
| >>> for inp in r: | ||||
| ...     print inp | ||||
| <label><input checked="checked" type="radio" name="beatle" value="J" /> John</label> | ||||
| <label><input type="radio" name="beatle" value="P" /> Paul</label> | ||||
| <label><input type="radio" name="beatle" value="G" /> George</label> | ||||
| <label><input type="radio" name="beatle" value="R" /> Ringo</label> | ||||
| >>> for inp in r: | ||||
| ...     print '%s<br />' % inp | ||||
| <label><input checked="checked" type="radio" name="beatle" value="J" /> John</label><br /> | ||||
| <label><input type="radio" name="beatle" value="P" /> Paul</label><br /> | ||||
| <label><input type="radio" name="beatle" value="G" /> George</label><br /> | ||||
| <label><input type="radio" name="beatle" value="R" /> Ringo</label><br /> | ||||
| >>> for inp in r: | ||||
| ...     print '<p>%s %s</p>' % (inp.tag(), inp.choice_label) | ||||
| <p><input checked="checked" type="radio" name="beatle" value="J" /> John</p> | ||||
| <p><input type="radio" name="beatle" value="P" /> Paul</p> | ||||
| <p><input type="radio" name="beatle" value="G" /> George</p> | ||||
| <p><input type="radio" name="beatle" value="R" /> Ringo</p> | ||||
| >>> for inp in r: | ||||
| ...     print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked()) | ||||
| beatle J J John True | ||||
| beatle J P Paul False | ||||
| beatle J G George False | ||||
| beatle J R Ringo False | ||||
|  | ||||
| # CharField ################################################################### | ||||
|  | ||||
| >>> f = CharField(required=False) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user