Ticket #3023: newforms.patch
File newforms.patch, 38.5 KB (added by , 18 years ago) |
---|
-
django/newforms/forms.py
3 3 """ 4 4 5 5 from fields import Field 6 from widgets import TextInput, Textarea 6 from widgets import TextInput, Textarea, Label 7 7 from util import ErrorDict, ErrorList, ValidationError 8 8 9 9 NON_FIELD_ERRORS = '__all__' … … 64 64 65 65 def as_table(self): 66 66 "Returns this form rendered as an HTML <table>." 67 output = u'\n'.join(['<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()])67 output = u'\n'.join(['<tr><td>%s:</td><td>%s</td></tr>' % BoundField(self, field, name).with_label() for name, field in self.fields.items()]) 68 68 return '<table>\n%s\n</table>' % output 69 69 70 70 def as_ul(self): 71 71 "Returns this form rendered as an HTML <ul>." 72 output = u'\n'.join(['<li>%s: %s</li>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()])72 output = u'\n'.join(['<li>%s: %s</li>' % BoundField(self, field, name).with_label() for name, field in self.fields.items()]) 73 73 return '<ul>\n%s\n</ul>' % output 74 74 75 75 def as_table_with_errors(self): … … 82 82 bf = BoundField(self, field, name) 83 83 if bf.errors: 84 84 output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors])) 85 output.append('<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), bf))85 output.append('<tr><td>%s:</td><td>%s</td></tr>' % bf.with_label()) 86 86 return '<table>\n%s\n</table>' % '\n'.join(output) 87 87 88 88 def as_ul_with_errors(self): … … 96 96 line = '<li>' 97 97 if bf.errors: 98 98 line += '<ul>%s</ul>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors]) 99 line += '%s: %s</li>' % (pretty_name(name), bf)99 line += '%s: %s</li>' % bf.with_label() 100 100 output.append(line) 101 101 return '<ul>\n%s\n</ul>' % '\n'.join(output) 102 102 … … 167 167 def as_textarea(self, attrs=None): 168 168 "Returns a string of HTML for representing this as a <textarea>." 169 169 return self.as_widget(Textarea(), attrs) 170 171 def with_label(self, widget=None, attrs=None): 172 """ 173 Returns a tuple of a label for this field and this field as an HTML 174 widget. 175 """ 176 if not widget: 177 widget = self._field.widget 178 widget = self.as_widget(widget) 179 label = Label().render(self._name, pretty_name(self._name)) 180 return label, widget 181 No newline at end of file -
django/newforms/widgets.py
6 6 'Widget', 'TextInput', 'PasswordInput', 'HiddenInput', 'FileInput', 7 7 'Textarea', 'CheckboxInput', 8 8 'Select', 'SelectMultiple', 9 'Label', 9 10 ) 10 11 11 12 from django.utils.html import escape 12 13 from itertools import chain 13 14 15 # 'id' HTML attribute format (where %s is the widget name). 16 ID_FORMAT = 'id_%s' 17 14 18 try: 15 19 set # Only available in Python 2.4+ 16 20 except NameError: 17 21 from sets import Set as set # Python 2.3 fallback 18 22 19 # Converts a dictionary to a single string with key="value", XML-style .20 # Assumes keys do not need to be XML-escaped.21 flatatt = lambda attrs: ' '.join(['%s="%s"' % (k, escape(v)) for k, v in attrs.items()])23 # Converts a dictionary to a single string with key="value", XML-style with 24 # leading space. Assumes keys do not need to be XML-escaped. 25 flatatt = lambda attrs: ''.join([' %s="%s"' % (k, escape(v)) for k, v in attrs.items()]) 22 26 23 27 class Widget(object): 24 28 requires_data_list = False # Determines whether render()'s 'value' argument should be a list. … … 27 31 28 32 def render(self, name, value): 29 33 raise NotImplementedError 34 35 def build_attrs(self, extra_attrs=None, **kwargs): 36 attrs = dict(self.attrs) 37 attrs.update(kwargs) 38 if extra_attrs: 39 attrs.update(extra_attrs) 40 if attrs.has_key('name') and not attrs.has_key('id'): 41 attrs['id'] = ID_FORMAT % attrs['name'] 42 return attrs 30 43 31 44 class Input(Widget): 32 45 "Base class for all <input> widgets (except type='checkbox', which is special)" 33 46 input_type = None # Subclasses must define this. 34 47 def render(self, name, value, attrs=None): 35 48 if value is None: value = '' 36 final_attrs = dict(self.attrs, type=self.input_type, name=name) 37 if attrs: 38 final_attrs.update(attrs) 49 final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) 39 50 if value != '': final_attrs['value'] = value # Only add the 'value' attribute if a value is non-empty. 40 return u'<input 51 return u'<input%s />' % flatatt(final_attrs) 41 52 42 53 class TextInput(Input): 43 54 input_type = 'text' … … 54 65 class Textarea(Widget): 55 66 def render(self, name, value, attrs=None): 56 67 if value is None: value = '' 57 final_attrs = dict(self.attrs, name=name) 58 if attrs: 59 final_attrs.update(attrs) 60 return u'<textarea %s>%s</textarea>' % (flatatt(final_attrs), escape(value)) 68 final_attrs = self.build_attrs(attrs, name=name) 69 return u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), escape(value)) 61 70 62 71 class CheckboxInput(Widget): 63 72 def render(self, name, value, attrs=None): 64 final_attrs = dict(self.attrs, type='checkbox', name=name) 65 if attrs: 66 final_attrs.update(attrs) 73 final_attrs = self.build_attrs(attrs, type='checkbox', name=name) 67 74 if value: final_attrs['checked'] = 'checked' 68 return u'<input 75 return u'<input%s />' % flatatt(final_attrs) 69 76 70 77 class Select(Widget): 71 78 def __init__(self, attrs=None, choices=()): … … 75 82 76 83 def render(self, name, value, attrs=None, choices=()): 77 84 if value is None: value = '' 78 final_attrs = dict(self.attrs, name=name) 79 if attrs: 80 final_attrs.update(attrs) 81 output = [u'<select %s>' % flatatt(final_attrs)] 85 final_attrs = self.build_attrs(attrs, name=name) 86 output = [u'<select%s>' % flatatt(final_attrs)] 82 87 str_value = str(value) # Normalize to string. 83 88 for option_value, option_label in chain(self.choices, choices): 84 89 selected_html = (str(option_value) == str_value) and ' selected="selected"' or '' … … 89 94 class SelectMultiple(Widget): 90 95 requires_data_list = True 91 96 def __init__(self, attrs=None, choices=()): 97 super(SelectMultiple, self).__init__(attrs) 92 98 # choices can be any iterable 93 self.attrs = attrs or {}94 99 self.choices = choices 95 100 96 101 def render(self, name, value, attrs=None, choices=()): 97 102 if value is None: value = [] 98 final_attrs = dict(self.attrs, name=name) 99 if attrs: 100 final_attrs.update(attrs) 101 output = [u'<select multiple="multiple" %s>' % flatatt(final_attrs)] 103 final_attrs = self.build_attrs(attrs, name=name) 104 output = [u'<select multiple="multiple"%s>' % flatatt(final_attrs)] 102 105 str_values = set([str(v) for v in value]) # Normalize to strings. 103 106 for option_value, option_label in chain(self.choices, choices): 104 107 selected_html = (str(option_value) in str_values) and ' selected="selected"' or '' … … 111 114 112 115 class CheckboxSelectMultiple(Widget): 113 116 pass 117 118 class Label(Widget): 119 def render(self, name, value, attrs=None): 120 if value is None: value = '' 121 if name: 122 # Only add the 'for' attribute if the widget name is not empty. 123 kwargs = {'for': ID_FORMAT % name} 124 else: 125 kwargs = {} 126 final_attrs = self.build_attrs(attrs, **kwargs) 127 return u'<label%s>%s</label>' % (flatatt(final_attrs), escape(value)) -
tests/regressiontests/forms/tests.py
7 7 8 8 >>> w = TextInput() 9 9 >>> w.render('email', '') 10 u'<input type="text" name="email" />'10 u'<input type="text" name="email" id="id_email" />' 11 11 >>> w.render('email', None) 12 u'<input type="text" name="email" />'12 u'<input type="text" name="email" id="id_email" />' 13 13 >>> w.render('email', 'test@example.com') 14 u'<input type="text" name="email" value="test@example.com" />'14 u'<input type="text" name="email" value="test@example.com" id="id_email" />' 15 15 >>> w.render('email', 'some "quoted" & ampersanded value') 16 u'<input type="text" name="email" value="some "quoted" & ampersanded value" />'16 u'<input type="text" name="email" value="some "quoted" & ampersanded value" id="id_email" />' 17 17 >>> w.render('email', 'test@example.com', attrs={'class': 'fun'}) 18 u'<input type="text" name="email" value="test@example.com" class="fun" />'18 u'<input id="id_email" type="text" name="email" value="test@example.com" class="fun" />' 19 19 20 20 You can also pass 'attrs' to the constructor: 21 21 >>> w = TextInput(attrs={'class': 'fun'}) 22 22 >>> w.render('email', '') 23 u'<input type="text" class="fun" name="email" />'23 u'<input id="id_email" type="text" class="fun" name="email" />' 24 24 >>> w.render('email', 'foo@example.com') 25 u'<input type="text" class="fun" value="foo@example.com" name="email" />'25 u'<input id="id_email" type="text" class="fun" value="foo@example.com" name="email" />' 26 26 27 27 'attrs' passed to render() get precedence over those passed to the constructor: 28 28 >>> w = TextInput(attrs={'class': 'pretty'}) 29 29 >>> w.render('email', '', attrs={'class': 'special'}) 30 u'<input type="text" class="special" name="email" />'30 u'<input id="id_email" type="text" class="special" name="email" />' 31 31 32 32 # PasswordInput Widget ############################################################ 33 33 34 34 >>> w = PasswordInput() 35 35 >>> w.render('email', '') 36 u'<input type="password" name="email" />'36 u'<input type="password" name="email" id="id_email" />' 37 37 >>> w.render('email', None) 38 u'<input type="password" name="email" />'38 u'<input type="password" name="email" id="id_email" />' 39 39 >>> w.render('email', 'test@example.com') 40 u'<input type="password" name="email" value="test@example.com" />'40 u'<input type="password" name="email" value="test@example.com" id="id_email" />' 41 41 >>> w.render('email', 'some "quoted" & ampersanded value') 42 u'<input type="password" name="email" value="some "quoted" & ampersanded value" />'42 u'<input type="password" name="email" value="some "quoted" & ampersanded value" id="id_email" />' 43 43 >>> w.render('email', 'test@example.com', attrs={'class': 'fun'}) 44 u'<input type="password" name="email" value="test@example.com" class="fun" />'44 u'<input id="id_email" type="password" name="email" value="test@example.com" class="fun" />' 45 45 46 46 You can also pass 'attrs' to the constructor: 47 47 >>> w = PasswordInput(attrs={'class': 'fun'}) 48 48 >>> w.render('email', '') 49 u'<input type="password" class="fun" name="email" />'49 u'<input id="id_email" type="password" class="fun" name="email" />' 50 50 >>> w.render('email', 'foo@example.com') 51 u'<input type="password" class="fun" value="foo@example.com" name="email" />'51 u'<input id="id_email" type="password" class="fun" value="foo@example.com" name="email" />' 52 52 53 53 'attrs' passed to render() get precedence over those passed to the constructor: 54 54 >>> w = PasswordInput(attrs={'class': 'pretty'}) 55 55 >>> w.render('email', '', attrs={'class': 'special'}) 56 u'<input type="password" class="special" name="email" />'56 u'<input id="id_email" type="password" class="special" name="email" />' 57 57 58 58 # HiddenInput Widget ############################################################ 59 59 60 60 >>> w = HiddenInput() 61 61 >>> w.render('email', '') 62 u'<input type="hidden" name="email" />'62 u'<input type="hidden" name="email" id="id_email" />' 63 63 >>> w.render('email', None) 64 u'<input type="hidden" name="email" />'64 u'<input type="hidden" name="email" id="id_email" />' 65 65 >>> w.render('email', 'test@example.com') 66 u'<input type="hidden" name="email" value="test@example.com" />'66 u'<input type="hidden" name="email" value="test@example.com" id="id_email" />' 67 67 >>> w.render('email', 'some "quoted" & ampersanded value') 68 u'<input type="hidden" name="email" value="some "quoted" & ampersanded value" />'68 u'<input type="hidden" name="email" value="some "quoted" & ampersanded value" id="id_email" />' 69 69 >>> w.render('email', 'test@example.com', attrs={'class': 'fun'}) 70 u'<input type="hidden" name="email" value="test@example.com" class="fun" />'70 u'<input id="id_email" type="hidden" name="email" value="test@example.com" class="fun" />' 71 71 72 72 You can also pass 'attrs' to the constructor: 73 73 >>> w = HiddenInput(attrs={'class': 'fun'}) 74 74 >>> w.render('email', '') 75 u'<input type="hidden" class="fun" name="email" />'75 u'<input id="id_email" type="hidden" class="fun" name="email" />' 76 76 >>> w.render('email', 'foo@example.com') 77 u'<input type="hidden" class="fun" value="foo@example.com" name="email" />'77 u'<input id="id_email" type="hidden" class="fun" value="foo@example.com" name="email" />' 78 78 79 79 'attrs' passed to render() get precedence over those passed to the constructor: 80 80 >>> w = HiddenInput(attrs={'class': 'pretty'}) 81 81 >>> w.render('email', '', attrs={'class': 'special'}) 82 u'<input type="hidden" class="special" name="email" />'82 u'<input id="id_email" type="hidden" class="special" name="email" />' 83 83 84 84 # FileInput Widget ############################################################ 85 85 86 86 >>> w = FileInput() 87 87 >>> w.render('email', '') 88 u'<input type="file" name="email" />'88 u'<input type="file" name="email" id="id_email" />' 89 89 >>> w.render('email', None) 90 u'<input type="file" name="email" />'90 u'<input type="file" name="email" id="id_email" />' 91 91 >>> w.render('email', 'test@example.com') 92 u'<input type="file" name="email" value="test@example.com" />'92 u'<input type="file" name="email" value="test@example.com" id="id_email" />' 93 93 >>> w.render('email', 'some "quoted" & ampersanded value') 94 u'<input type="file" name="email" value="some "quoted" & ampersanded value" />'94 u'<input type="file" name="email" value="some "quoted" & ampersanded value" id="id_email" />' 95 95 >>> w.render('email', 'test@example.com', attrs={'class': 'fun'}) 96 u'<input type="file" name="email" value="test@example.com" class="fun" />'96 u'<input id="id_email" type="file" name="email" value="test@example.com" class="fun" />' 97 97 98 98 You can also pass 'attrs' to the constructor: 99 99 >>> w = FileInput(attrs={'class': 'fun'}) 100 100 >>> w.render('email', '') 101 u'<input type="file" class="fun" name="email" />'101 u'<input id="id_email" type="file" class="fun" name="email" />' 102 102 >>> w.render('email', 'foo@example.com') 103 u'<input type="file" class="fun" value="foo@example.com" name="email" />'103 u'<input id="id_email" type="file" class="fun" value="foo@example.com" name="email" />' 104 104 105 105 'attrs' passed to render() get precedence over those passed to the constructor: 106 106 >>> w = HiddenInput(attrs={'class': 'pretty'}) 107 107 >>> w.render('email', '', attrs={'class': 'special'}) 108 u'<input type="hidden" class="special" name="email" />'108 u'<input id="id_email" type="hidden" class="special" name="email" />' 109 109 110 110 # Textarea Widget ############################################################# 111 111 112 112 >>> w = Textarea() 113 113 >>> w.render('msg', '') 114 u'<textarea name="msg" ></textarea>'114 u'<textarea name="msg" id="id_msg"></textarea>' 115 115 >>> w.render('msg', None) 116 u'<textarea name="msg" ></textarea>'116 u'<textarea name="msg" id="id_msg"></textarea>' 117 117 >>> w.render('msg', 'value') 118 u'<textarea name="msg" >value</textarea>'118 u'<textarea name="msg" id="id_msg">value</textarea>' 119 119 >>> w.render('msg', 'some "quoted" & ampersanded value') 120 u'<textarea name="msg" >some "quoted" & ampersanded value</textarea>'120 u'<textarea name="msg" id="id_msg">some "quoted" & ampersanded value</textarea>' 121 121 >>> w.render('msg', 'value', attrs={'class': 'pretty'}) 122 u'<textarea name="msg" class="pretty">value</textarea>'122 u'<textarea id="id_msg" name="msg" class="pretty">value</textarea>' 123 123 124 124 You can also pass 'attrs' to the constructor: 125 125 >>> w = Textarea(attrs={'class': 'pretty'}) 126 126 >>> w.render('msg', '') 127 u'<textarea class="pretty" name="msg"></textarea>'127 u'<textarea id="id_msg" class="pretty" name="msg"></textarea>' 128 128 >>> w.render('msg', 'example') 129 u'<textarea class="pretty" name="msg">example</textarea>'129 u'<textarea id="id_msg" class="pretty" name="msg">example</textarea>' 130 130 131 131 'attrs' passed to render() get precedence over those passed to the constructor: 132 132 >>> w = Textarea(attrs={'class': 'pretty'}) 133 133 >>> w.render('msg', '', attrs={'class': 'special'}) 134 u'<textarea class="special" name="msg"></textarea>'134 u'<textarea id="id_msg" class="special" name="msg"></textarea>' 135 135 136 136 # CheckboxInput Widget ######################################################## 137 137 138 138 >>> w = CheckboxInput() 139 139 >>> w.render('is_cool', '') 140 u'<input type="checkbox" name="is_cool" />'140 u'<input type="checkbox" name="is_cool" id="id_is_cool" />' 141 141 >>> w.render('is_cool', False) 142 u'<input type="checkbox" name="is_cool" />'142 u'<input type="checkbox" name="is_cool" id="id_is_cool" />' 143 143 >>> w.render('is_cool', True) 144 u'<input checked="checked" type="checkbox" name="is_cool" />'144 u'<input checked="checked" type="checkbox" name="is_cool" id="id_is_cool" />' 145 145 >>> w.render('is_cool', False, attrs={'class': 'pretty'}) 146 u'<input type="checkbox" name="is_cool" class="pretty" />'146 u'<input id="id_is_cool" type="checkbox" name="is_cool" class="pretty" />' 147 147 148 148 You can also pass 'attrs' to the constructor: 149 149 >>> w = CheckboxInput(attrs={'class': 'pretty'}) 150 150 >>> w.render('is_cool', '') 151 u'<input type="checkbox" class="pretty" name="is_cool" />'151 u'<input id="id_is_cool" type="checkbox" class="pretty" name="is_cool" />' 152 152 153 153 'attrs' passed to render() get precedence over those passed to the constructor: 154 154 >>> w = CheckboxInput(attrs={'class': 'pretty'}) 155 155 >>> w.render('is_cool', '', attrs={'class': 'special'}) 156 u'<input type="checkbox" class="special" name="is_cool" />'156 u'<input id="id_is_cool" type="checkbox" class="special" name="is_cool" />' 157 157 158 158 # Select Widget ############################################################### 159 159 160 160 >>> w = Select() 161 161 >>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 162 <select name="beatle" >162 <select name="beatle" id="id_beatle"> 163 163 <option value="J" selected="selected">John</option> 164 164 <option value="P">Paul</option> 165 165 <option value="G">George</option> … … 168 168 169 169 If the value is None, none of the options are selected: 170 170 >>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 171 <select name="beatle" >171 <select name="beatle" id="id_beatle"> 172 172 <option value="J">John</option> 173 173 <option value="P">Paul</option> 174 174 <option value="G">George</option> … … 177 177 178 178 If the value corresponds to a label (but not to an option value), none of the options are selected: 179 179 >>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 180 <select name="beatle" >180 <select name="beatle" id="id_beatle"> 181 181 <option value="J">John</option> 182 182 <option value="P">Paul</option> 183 183 <option value="G">George</option> … … 186 186 187 187 The value is compared to its str(): 188 188 >>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]) 189 <select name="num" >189 <select name="num" id="id_num"> 190 190 <option value="1">1</option> 191 191 <option value="2" selected="selected">2</option> 192 192 <option value="3">3</option> 193 193 </select> 194 194 >>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]) 195 <select name="num" >195 <select name="num" id="id_num"> 196 196 <option value="1">1</option> 197 197 <option value="2" selected="selected">2</option> 198 198 <option value="3">3</option> 199 199 </select> 200 200 >>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]) 201 <select name="num" >201 <select name="num" id="id_num"> 202 202 <option value="1">1</option> 203 203 <option value="2" selected="selected">2</option> 204 204 <option value="3">3</option> … … 209 209 ... for i in range(5): 210 210 ... yield (i, i) 211 211 >>> print w.render('num', 2, choices=get_choices()) 212 <select name="num" >212 <select name="num" id="id_num"> 213 213 <option value="0">0</option> 214 214 <option value="1">1</option> 215 215 <option value="2" selected="selected">2</option> … … 220 220 You can also pass 'choices' to the constructor: 221 221 >>> w = Select(choices=[(1, 1), (2, 2), (3, 3)]) 222 222 >>> print w.render('num', 2) 223 <select name="num" >223 <select name="num" id="id_num"> 224 224 <option value="1">1</option> 225 225 <option value="2" selected="selected">2</option> 226 226 <option value="3">3</option> … … 228 228 229 229 If 'choices' is passed to both the constructor and render(), then they'll both be in the output: 230 230 >>> print w.render('num', 2, choices=[(4, 4), (5, 5)]) 231 <select name="num" >231 <select name="num" id="id_num"> 232 232 <option value="1">1</option> 233 233 <option value="2" selected="selected">2</option> 234 234 <option value="3">3</option> … … 240 240 241 241 >>> w = SelectMultiple() 242 242 >>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 243 <select multiple="multiple" name="beatles" >243 <select multiple="multiple" name="beatles" id="id_beatles"> 244 244 <option value="J" selected="selected">John</option> 245 245 <option value="P">Paul</option> 246 246 <option value="G">George</option> 247 247 <option value="R">Ringo</option> 248 248 </select> 249 249 >>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 250 <select multiple="multiple" name="beatles" >250 <select multiple="multiple" name="beatles" id="id_beatles"> 251 251 <option value="J" selected="selected">John</option> 252 252 <option value="P" selected="selected">Paul</option> 253 253 <option value="G">George</option> 254 254 <option value="R">Ringo</option> 255 255 </select> 256 256 >>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 257 <select multiple="multiple" name="beatles" >257 <select multiple="multiple" name="beatles" id="id_beatles"> 258 258 <option value="J" selected="selected">John</option> 259 259 <option value="P" selected="selected">Paul</option> 260 260 <option value="G">George</option> … … 263 263 264 264 If the value is None, none of the options are selected: 265 265 >>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 266 <select multiple="multiple" name="beatles" >266 <select multiple="multiple" name="beatles" id="id_beatles"> 267 267 <option value="J">John</option> 268 268 <option value="P">Paul</option> 269 269 <option value="G">George</option> … … 272 272 273 273 If the value corresponds to a label (but not to an option value), none of the options are selected: 274 274 >>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 275 <select multiple="multiple" name="beatles" >275 <select multiple="multiple" name="beatles" id="id_beatles"> 276 276 <option value="J">John</option> 277 277 <option value="P">Paul</option> 278 278 <option value="G">George</option> … … 281 281 282 282 If multiple values are given, but some of them are not valid, the valid ones are selected: 283 283 >>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 284 <select multiple="multiple" name="beatles" >284 <select multiple="multiple" name="beatles" id="id_beatles"> 285 285 <option value="J" selected="selected">John</option> 286 286 <option value="P">Paul</option> 287 287 <option value="G" selected="selected">George</option> … … 290 290 291 291 The value is compared to its str(): 292 292 >>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]) 293 <select multiple="multiple" name="nums" >293 <select multiple="multiple" name="nums" id="id_nums"> 294 294 <option value="1">1</option> 295 295 <option value="2" selected="selected">2</option> 296 296 <option value="3">3</option> 297 297 </select> 298 298 >>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]) 299 <select multiple="multiple" name="nums" >299 <select multiple="multiple" name="nums" id="id_nums"> 300 300 <option value="1">1</option> 301 301 <option value="2" selected="selected">2</option> 302 302 <option value="3">3</option> 303 303 </select> 304 304 >>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]) 305 <select multiple="multiple" name="nums" >305 <select multiple="multiple" name="nums" id="id_nums"> 306 306 <option value="1">1</option> 307 307 <option value="2" selected="selected">2</option> 308 308 <option value="3">3</option> … … 313 313 ... for i in range(5): 314 314 ... yield (i, i) 315 315 >>> print w.render('nums', [2], choices=get_choices()) 316 <select multiple="multiple" name="nums" >316 <select multiple="multiple" name="nums" id="id_nums"> 317 317 <option value="0">0</option> 318 318 <option value="1">1</option> 319 319 <option value="2" selected="selected">2</option> … … 324 324 You can also pass 'choices' to the constructor: 325 325 >>> w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)]) 326 326 >>> print w.render('nums', [2]) 327 <select multiple="multiple" name="nums" >327 <select multiple="multiple" name="nums" id="id_nums"> 328 328 <option value="1">1</option> 329 329 <option value="2" selected="selected">2</option> 330 330 <option value="3">3</option> … … 332 332 333 333 If 'choices' is passed to both the constructor and render(), then they'll both be in the output: 334 334 >>> print w.render('nums', [2], choices=[(4, 4), (5, 5)]) 335 <select multiple="multiple" name="nums" >335 <select multiple="multiple" name="nums" id="id_nums"> 336 336 <option value="1">1</option> 337 337 <option value="2" selected="selected">2</option> 338 338 <option value="3">3</option> … … 771 771 >>> p = Person() 772 772 >>> print p 773 773 <table> 774 <tr><td> First name:</td><td><input type="text" name="first_name" /></td></tr>775 <tr><td> Last name:</td><td><input type="text" name="last_name" /></td></tr>776 <tr><td> Birthday:</td><td><input type="text" name="birthday" /></td></tr>774 <tr><td><label for="id_first_name">First name</label>:</td><td><input type="text" name="first_name" id="id_first_name" /></td></tr> 775 <tr><td><label for="id_last_name">Last name</label>:</td><td><input type="text" name="last_name" id="id_last_name" /></td></tr> 776 <tr><td><label for="id_birthday">Birthday</label>:</td><td><input type="text" name="birthday" id="id_birthday" /></td></tr> 777 777 </table> 778 778 >>> print p.as_table() 779 779 <table> 780 <tr><td> First name:</td><td><input type="text" name="first_name" /></td></tr>781 <tr><td> Last name:</td><td><input type="text" name="last_name" /></td></tr>782 <tr><td> Birthday:</td><td><input type="text" name="birthday" /></td></tr>780 <tr><td><label for="id_first_name">First name</label>:</td><td><input type="text" name="first_name" id="id_first_name" /></td></tr> 781 <tr><td><label for="id_last_name">Last name</label>:</td><td><input type="text" name="last_name" id="id_last_name" /></td></tr> 782 <tr><td><label for="id_birthday">Birthday</label>:</td><td><input type="text" name="birthday" id="id_birthday" /></td></tr> 783 783 </table> 784 784 >>> print p.as_ul() 785 785 <ul> 786 <li> First name: <input type="text" name="first_name" /></li>787 <li> Last name: <input type="text" name="last_name" /></li>788 <li> Birthday: <input type="text" name="birthday" /></li>786 <li><label for="id_first_name">First name</label>: <input type="text" name="first_name" id="id_first_name" /></li> 787 <li><label for="id_last_name">Last name</label>: <input type="text" name="last_name" id="id_last_name" /></li> 788 <li><label for="id_birthday">Birthday</label>: <input type="text" name="birthday" id="id_birthday" /></li> 789 789 </ul> 790 790 >>> print p.as_table_with_errors() 791 791 <table> 792 792 <tr><td colspan="2"><ul><li>This field is required.</li></ul></td></tr> 793 <tr><td> First name:</td><td><input type="text" name="first_name" /></td></tr>793 <tr><td><label for="id_first_name">First name</label>:</td><td><input type="text" name="first_name" id="id_first_name" /></td></tr> 794 794 <tr><td colspan="2"><ul><li>This field is required.</li></ul></td></tr> 795 <tr><td> Last name:</td><td><input type="text" name="last_name" /></td></tr>795 <tr><td><label for="id_last_name">Last name</label>:</td><td><input type="text" name="last_name" id="id_last_name" /></td></tr> 796 796 <tr><td colspan="2"><ul><li>This field is required.</li></ul></td></tr> 797 <tr><td> Birthday:</td><td><input type="text" name="birthday" /></td></tr>797 <tr><td><label for="id_birthday">Birthday</label>:</td><td><input type="text" name="birthday" id="id_birthday" /></td></tr> 798 798 </table> 799 799 >>> print p.as_ul_with_errors() 800 800 <ul> 801 <li><ul><li>This field is required.</li></ul> First name: <input type="text" name="first_name" /></li>802 <li><ul><li>This field is required.</li></ul> Last name: <input type="text" name="last_name" /></li>803 <li><ul><li>This field is required.</li></ul> Birthday: <input type="text" name="birthday" /></li>801 <li><ul><li>This field is required.</li></ul><label for="id_first_name">First name</label>: <input type="text" name="first_name" id="id_first_name" /></li> 802 <li><ul><li>This field is required.</li></ul><label for="id_last_name">Last name</label>: <input type="text" name="last_name" id="id_last_name" /></li> 803 <li><ul><li>This field is required.</li></ul><label for="id_birthday">Birthday</label>: <input type="text" name="birthday" id="id_birthday" /></li> 804 804 </ul> 805 805 806 806 >>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'}) … … 815 815 >>> p.clean() 816 816 {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} 817 817 >>> print p['first_name'] 818 <input type="text" name="first_name" value="John" />818 <input type="text" name="first_name" value="John" id="id_first_name" /> 819 819 >>> print p['last_name'] 820 <input type="text" name="last_name" value="Lennon" />820 <input type="text" name="last_name" value="Lennon" id="id_last_name" /> 821 821 >>> print p['birthday'] 822 <input type="text" name="birthday" value="1940-10-9" />822 <input type="text" name="birthday" value="1940-10-9" id="id_birthday" /> 823 823 >>> for boundfield in p: 824 824 ... print boundfield 825 <input type="text" name="first_name" value="John" />826 <input type="text" name="last_name" value="Lennon" />827 <input type="text" name="birthday" value="1940-10-9" />825 <input type="text" name="first_name" value="John" id="id_first_name" /> 826 <input type="text" name="last_name" value="Lennon" id="id_last_name" /> 827 <input type="text" name="birthday" value="1940-10-9" id="id_birthday" /> 828 828 >>> print p 829 829 <table> 830 <tr><td> First name:</td><td><input type="text" name="first_name" value="John" /></td></tr>831 <tr><td> Last name:</td><td><input type="text" name="last_name" value="Lennon" /></td></tr>832 <tr><td> Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /></td></tr>830 <tr><td><label for="id_first_name">First name</label>:</td><td><input type="text" name="first_name" value="John" id="id_first_name" /></td></tr> 831 <tr><td><label for="id_last_name">Last name</label>:</td><td><input type="text" name="last_name" value="Lennon" id="id_last_name" /></td></tr> 832 <tr><td><label for="id_birthday">Birthday</label>:</td><td><input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></td></tr> 833 833 </table> 834 834 835 835 >>> p = Person({'last_name': u'Lennon'}) … … 856 856 857 857 >>> p = Person() 858 858 >>> print p['first_name'] 859 <input type="text" name="first_name" />859 <input type="text" name="first_name" id="id_first_name" /> 860 860 >>> print p['last_name'] 861 <input type="text" name="last_name" />861 <input type="text" name="last_name" id="id_last_name" /> 862 862 >>> print p['birthday'] 863 <input type="text" name="birthday" />863 <input type="text" name="birthday" id="id_birthday" /> 864 864 865 865 >>> class SignupForm(Form): 866 866 ... email = EmailField() 867 867 ... get_spam = BooleanField() 868 868 >>> f = SignupForm() 869 869 >>> print f['email'] 870 <input type="text" name="email" />870 <input type="text" name="email" id="id_email" /> 871 871 >>> print f['get_spam'] 872 <input type="checkbox" name="get_spam" />872 <input type="checkbox" name="get_spam" id="id_get_spam" /> 873 873 874 874 >>> f = SignupForm({'email': 'test@example.com', 'get_spam': True}) 875 875 >>> print f['email'] 876 <input type="text" name="email" value="test@example.com" />876 <input type="text" name="email" value="test@example.com" id="id_email" /> 877 877 >>> print f['get_spam'] 878 <input checked="checked" type="checkbox" name="get_spam" />878 <input checked="checked" type="checkbox" name="get_spam" id="id_get_spam" /> 879 879 880 880 Any Field can have a Widget class passed to its constructor: 881 881 >>> class ContactForm(Form): … … 883 883 ... message = CharField(widget=Textarea) 884 884 >>> f = ContactForm() 885 885 >>> print f['subject'] 886 <input type="text" name="subject" />886 <input type="text" name="subject" id="id_subject" /> 887 887 >>> print f['message'] 888 <textarea name="message" ></textarea>888 <textarea name="message" id="id_message"></textarea> 889 889 890 890 as_textarea() and as_text() are shortcuts for changing the output widget type: 891 891 >>> f['subject'].as_textarea() 892 u'<textarea name="subject" ></textarea>'892 u'<textarea name="subject" id="id_subject"></textarea>' 893 893 >>> f['message'].as_text() 894 u'<input type="text" name="message" />'894 u'<input type="text" name="message" id="id_message" />' 895 895 896 896 The 'widget' parameter to a Field can also be an instance: 897 897 >>> class ContactForm(Form): … … 899 899 ... message = CharField(widget=Textarea(attrs={'rows': 80, 'cols': 20})) 900 900 >>> f = ContactForm() 901 901 >>> print f['message'] 902 <textarea rows="80" cols="20" name="message"></textarea>902 <textarea id="id_message" rows="80" cols="20" name="message"></textarea> 903 903 904 904 Instance-level attrs are *not* carried over to as_textarea() and as_text(): 905 905 >>> f['message'].as_text() 906 u'<input type="text" name="message" />'906 u'<input type="text" name="message" id="id_message" />' 907 907 >>> f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}) 908 908 >>> f['subject'].as_textarea() 909 u'<textarea name="subject" >Hello</textarea>'909 u'<textarea name="subject" id="id_subject">Hello</textarea>' 910 910 >>> f['message'].as_text() 911 u'<input type="text" name="message" value="I love you." />'911 u'<input type="text" name="message" value="I love you." id="id_message" />' 912 912 913 913 For a form with a <select>, use ChoiceField: 914 914 >>> class FrameworkForm(Form): … … 916 916 ... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')]) 917 917 >>> f = FrameworkForm() 918 918 >>> print f['language'] 919 <select name="language" >919 <select name="language" id="id_language"> 920 920 <option value="P">Python</option> 921 921 <option value="J">Java</option> 922 922 </select> 923 923 >>> f = FrameworkForm({'name': 'Django', 'language': 'P'}) 924 924 >>> print f['language'] 925 <select name="language" >925 <select name="language" id="id_language"> 926 926 <option value="P" selected="selected">Python</option> 927 927 <option value="J">Java</option> 928 928 </select> … … 933 933 ... composers = MultipleChoiceField() 934 934 >>> f = SongForm() 935 935 >>> print f['composers'] 936 <select multiple="multiple" name="composers" >936 <select multiple="multiple" name="composers" id="id_composers"> 937 937 </select> 938 938 >>> class SongForm(Form): 939 939 ... name = CharField() 940 940 ... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')]) 941 941 >>> f = SongForm() 942 942 >>> print f['composers'] 943 <select multiple="multiple" name="composers" >943 <select multiple="multiple" name="composers" id="id_composers"> 944 944 <option value="J">John Lennon</option> 945 945 <option value="P">Paul McCartney</option> 946 946 </select> 947 947 >>> f = SongForm({'name': 'Yesterday', 'composers': ['P']}) 948 948 >>> print f['name'] 949 <input type="text" name="name" value="Yesterday" />949 <input type="text" name="name" value="Yesterday" id="id_name" /> 950 950 >>> print f['composers'] 951 <select multiple="multiple" name="composers" >951 <select multiple="multiple" name="composers" id="id_composers"> 952 952 <option value="J">John Lennon</option> 953 953 <option value="P" selected="selected">Paul McCartney</option> 954 954 </select> … … 993 993 >>> f = UserRegistration() 994 994 >>> print f.as_table() 995 995 <table> 996 <tr><td> Username:</td><td><input type="text" name="username" /></td></tr>997 <tr><td> Password1:</td><td><input type="password" name="password1" /></td></tr>998 <tr><td> Password2:</td><td><input type="password" name="password2" /></td></tr>996 <tr><td><label for="id_username">Username</label>:</td><td><input type="text" name="username" id="id_username" /></td></tr> 997 <tr><td><label for="id_password1">Password1</label>:</td><td><input type="password" name="password1" id="id_password1" /></td></tr> 998 <tr><td><label for="id_password2">Password2</label>:</td><td><input type="password" name="password2" id="id_password2" /></td></tr> 999 999 </table> 1000 1000 >>> f.errors() 1001 1001 {'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']} … … 1004 1004 {'__all__': [u'Please make sure your passwords match.']} 1005 1005 >>> print f.as_table() 1006 1006 <table> 1007 <tr><td> Username:</td><td><input type="text" name="username" value="adrian" /></td></tr>1008 <tr><td> Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr>1009 <tr><td> Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr>1007 <tr><td><label for="id_username">Username</label>:</td><td><input type="text" name="username" value="adrian" id="id_username" /></td></tr> 1008 <tr><td><label for="id_password1">Password1</label>:</td><td><input type="password" name="password1" value="foo" id="id_password1" /></td></tr> 1009 <tr><td><label for="id_password2">Password2</label>:</td><td><input type="password" name="password2" value="bar" id="id_password2" /></td></tr> 1010 1010 </table> 1011 1011 >>> print f.as_table_with_errors() 1012 1012 <table> 1013 1013 <tr><td colspan="2"><ul><li>Please make sure your passwords match.</li></ul></td></tr> 1014 <tr><td> Username:</td><td><input type="text" name="username" value="adrian" /></td></tr>1015 <tr><td> Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr>1016 <tr><td> Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr>1014 <tr><td><label for="id_username">Username</label>:</td><td><input type="text" name="username" value="adrian" id="id_username" /></td></tr> 1015 <tr><td><label for="id_password1">Password1</label>:</td><td><input type="password" name="password1" value="foo" id="id_password1" /></td></tr> 1016 <tr><td><label for="id_password2">Password2</label>:</td><td><input type="password" name="password2" value="bar" id="id_password2" /></td></tr> 1017 1017 </table> 1018 1018 >>> print f.as_ul_with_errors() 1019 1019 <ul> 1020 1020 <li><ul><li>Please make sure your passwords match.</li></ul></li> 1021 <li> Username: <input type="text" name="username" value="adrian" /></li>1022 <li> Password1: <input type="password" name="password1" value="foo" /></li>1023 <li> Password2: <input type="password" name="password2" value="bar" /></li>1021 <li><label for="id_username">Username</label>: <input type="text" name="username" value="adrian" id="id_username" /></li> 1022 <li><label for="id_password1">Password1</label>: <input type="password" name="password1" value="foo" id="id_password1" /></li> 1023 <li><label for="id_password2">Password2</label>: <input type="password" name="password2" value="bar" id="id_password2" /></li> 1024 1024 </ul> 1025 1025 >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}) 1026 1026 >>> f.errors()