Ticket #3568: htmlnewforms.2.diff
File htmlnewforms.2.diff, 16.4 KB (added by , 18 years ago) |
---|
-
django/newforms/forms.py
5 5 from django.utils.datastructures import SortedDict, MultiValueDict 6 6 from django.utils.html import escape 7 7 from fields import Field 8 from serializations import * 8 9 from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput 9 10 from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError 10 11 import copy 11 12 12 __all__ = ('BaseForm', 'Form' )13 __all__ = ('BaseForm', 'Form', 'SERIALIZATION_XHTML', 'SERIALIZATION_HTML401', 'SERIALIZATION_DEFAULT', 'SERIALIZATION_HTML_COMPATIBLE_XHTML1') 13 14 14 15 NON_FIELD_ERRORS = '__all__' 15 16 … … 107 108 """ 108 109 return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name 109 110 110 def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row ):111 def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, serialization=SERIALIZATION_DEFAULT): 111 112 "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()." 112 113 top_errors = self.non_field_errors() # Errors that should be displayed above all fields. 113 114 output, hidden_fields = [], [] 114 115 for name, field in self.fields.items(): 115 bf = BoundField(self, field, name )116 bf = BoundField(self, field, name,serialization) 116 117 bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable. 117 118 if bf.is_hidden: 118 119 if bf_errors: … … 139 140 output.append(str_hidden) 140 141 return u'\n'.join(output) 141 142 142 def as_table(self): 143 "Returns this form rendered as HTML <tr>s -- excluding the <table></table>." 144 return self._html_output(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'<br />%s', False) 143 def as_table(self,serialization=SERIALIZATION_DEFAULT): 144 """ 145 Returns this form rendered as HTML <tr>s -- excluding the <table></table>. 146 Takes a serialization as an optional argument. 147 """ 148 br = u'<br' + end_empty_element(u'br',serialization) 149 return self._html_output(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'' + br + '%s', False, serialization) 145 150 146 def as_ul(self): 147 "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>." 148 return self._html_output(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False) 151 def as_ul(self,serialization=SERIALIZATION_DEFAULT): 152 """ 153 Returns this form rendered as HTML <li>s -- excluding the <ul></ul>. 154 Takes a serialization as an optional argument. 155 """ 156 return self._html_output(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False, serialization) 149 157 150 def as_p(self): 151 "Returns this form rendered as HTML <p>s." 152 return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True) 158 def as_p(self,serialization=SERIALIZATION_DEFAULT): 159 """ 160 Returns this form rendered as HTML <p>s. 161 Takes a serialization as an optional argument. 162 """ 163 return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True, serialization) 164 165 def as_div(self,serialization=SERIALIZATION_DEFAULT): 166 """ 167 Returns this form rendered as HTML <div>s. 168 Takes a serialization as an optional argument. 169 """ 170 return self._html_output(u'<div>%(label)s %(field)s%(help_text)s</div>', u'<div>%s</div>', '</div>', u' %s', True, serialization) 153 171 154 172 def non_field_errors(self): 155 173 """ … … 209 227 210 228 class BoundField(StrAndUnicode): 211 229 "A Field plus data" 212 def __init__(self, form, field, name ):230 def __init__(self, form, field, name,serialization=SERIALIZATION_DEFAULT): 213 231 self.form = form 214 232 self.field = field 215 233 self.name = name … … 219 237 else: 220 238 self.label = self.field.label 221 239 self.help_text = field.help_text or '' 240 self.serialization=serialization 222 241 223 242 def __unicode__(self): 224 243 "Renders this field as an HTML widget." 225 244 # Use the 'widget' attribute on the field to determine which type 226 245 # of HTML widget to use. 227 value = self.as_widget(self.field.widget) 246 value = self.as_widget(widget=self.field.widget, 247 attrs=None, 248 serialization=self.serialization) 228 249 if not isinstance(value, basestring): 229 250 # Some Widget render() methods -- notably RadioSelect -- return a 230 251 # "special" object rather than a string. Call the __str__() on that … … 240 261 return self.form.errors.get(self.name, ErrorList()) 241 262 errors = property(_errors) 242 263 243 def as_widget(self, widget, attrs=None ):264 def as_widget(self, widget, attrs=None, serialization=SERIALIZATION_DEFAULT): 244 265 attrs = attrs or {} 245 266 auto_id = self.auto_id 246 267 if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'): … … 249 270 data = self.form.initial.get(self.name, self.field.initial) 250 271 else: 251 272 data = self.data 252 return widget.render(self.html_name, data, attrs=attrs )273 return widget.render(self.html_name, data, attrs=attrs, serialization=serialization) 253 274 254 def as_text(self, attrs=None ):275 def as_text(self, attrs=None, serialization=SERIALIZATION_DEFAULT): 255 276 """ 256 277 Returns a string of HTML for representing this as an <input type="text">. 257 278 """ 258 return self.as_widget(TextInput(), attrs )279 return self.as_widget(TextInput(), attrs, serialization) 259 280 260 def as_textarea(self, attrs=None ):281 def as_textarea(self, attrs=None, serialization=SERIALIZATION_DEFAULT): 261 282 "Returns a string of HTML for representing this as a <textarea>." 262 283 return self.as_widget(Textarea(), attrs) 263 284 264 def as_hidden(self, attrs=None ):285 def as_hidden(self, attrs=None, serialization=SERIALIZATION_DEFAULT): 265 286 """ 266 287 Returns a string of HTML for representing this as an <input type="hidden">. 267 288 """ 268 return self.as_widget(self.field.hidden_widget(), attrs )289 return self.as_widget(self.field.hidden_widget(), attrs, serialization) 269 290 270 291 def _data(self): 271 292 """ -
django/newforms/widgets.py
14 14 from django.utils.html import escape 15 15 from django.utils.translation import gettext 16 16 from itertools import chain 17 from serializations import end_empty_element, SERIALIZATION_DEFAULT 17 18 18 19 try: 19 20 set # Only available in Python 2.4+ … … 26 27 def __init__(self, attrs=None): 27 28 self.attrs = attrs or {} 28 29 29 def render(self, name, value, attrs=None ):30 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 30 31 """ 31 32 Returns this Widget rendered as HTML, as a Unicode string. 32 33 … … 69 70 """ 70 71 input_type = None # Subclasses must define this. 71 72 72 def render(self, name, value, attrs=None ):73 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 73 74 if value is None: value = '' 74 75 final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) 75 76 if value != '': final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty. 76 return u'<input%s />' % flatatt(final_attrs)77 return u'<input%s%s' % (flatatt(final_attrs), end_empty_element(u'input',serialization)); 77 78 78 79 class TextInput(Input): 79 80 input_type = 'text' … … 85 86 self.attrs = attrs or {} 86 87 self.render_value = render_value 87 88 88 def render(self, name, value, attrs=None ):89 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 89 90 if not self.render_value: value=None 90 return super(PasswordInput, self).render(name, value, attrs )91 return super(PasswordInput, self).render(name, value, attrs, serialization) 91 92 92 93 class HiddenInput(Input): 93 94 input_type = 'hidden' … … 103 104 self.attrs = attrs or {} 104 105 self.choices = choices 105 106 106 def render(self, name, value, attrs=None, choices=() ):107 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 107 108 if value is None: value = [] 108 109 final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) 109 return u'\n'.join([(u'<input%s />' % flatatt(dict(value=smart_unicode(v), **final_attrs))) for v in value])110 return u'\n'.join([(u'<input%s%s' % (flatatt(dict(value=smart_unicode(v), **final_attrs)), end_empty_element(u'input',serialization))) for v in value]) 110 111 111 112 def value_from_datadict(self, data, name): 112 113 if isinstance(data, MultiValueDict): … … 117 118 input_type = 'file' 118 119 119 120 class Textarea(Widget): 120 def render(self, name, value, attrs=None ):121 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 121 122 if value is None: value = '' 122 123 value = smart_unicode(value) 123 124 final_attrs = self.build_attrs(attrs, name=name) … … 130 131 self.attrs = attrs or {} 131 132 self.check_test = check_test 132 133 133 def render(self, name, value, attrs=None ):134 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 134 135 final_attrs = self.build_attrs(attrs, type='checkbox', name=name) 135 136 try: 136 137 result = self.check_test(value) … … 140 141 final_attrs['checked'] = 'checked' 141 142 if value not in ('', True, False, None): 142 143 final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty. 143 return u'<input%s />' % flatatt(final_attrs)144 return u'<input%s%s' % (flatatt(final_attrs),end_empty_element(u'input',serialization)) 144 145 145 146 class Select(Widget): 146 147 def __init__(self, attrs=None, choices=()): … … 150 151 # more than once. 151 152 self.choices = list(choices) 152 153 153 def render(self, name, value, attrs=None, choices=() ):154 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 154 155 if value is None: value = '' 155 156 final_attrs = self.build_attrs(attrs, name=name) 156 157 output = [u'<select%s>' % flatatt(final_attrs)] … … 170 171 choices = ((u'1', gettext('Unknown')), (u'2', gettext('Yes')), (u'3', gettext('No'))) 171 172 super(NullBooleanSelect, self).__init__(attrs, choices) 172 173 173 def render(self, name, value, attrs=None, choices=() ):174 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 174 175 try: 175 176 value = {True: u'2', False: u'3', u'2': u'2', u'3': u'3'}[value] 176 177 except KeyError: 177 178 value = u'1' 178 return super(NullBooleanSelect, self).render(name, value, attrs, choices )179 return super(NullBooleanSelect, self).render(name, value, attrs, choices, serialization) 179 180 180 181 def value_from_datadict(self, data, name): 181 182 value = data.get(name, None) … … 187 188 self.attrs = attrs or {} 188 189 self.choices = choices 189 190 190 def render(self, name, value, attrs=None, choices=() ):191 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 191 192 if value is None: value = [] 192 193 final_attrs = self.build_attrs(attrs, name=name) 193 194 output = [u'<select multiple="multiple"%s>' % flatatt(final_attrs)] … … 206 207 207 208 class RadioInput(StrAndUnicode): 208 209 "An object used by RadioFieldRenderer that represents a single <input type='radio'>." 209 def __init__(self, name, value, attrs, choice, index ):210 def __init__(self, name, value, attrs, choice, index, serialization=SERIALIZATION_DEFAULT): 210 211 self.name, self.value = name, value 211 212 self.attrs = attrs 212 213 self.choice_value = smart_unicode(choice[0]) 213 214 self.choice_label = smart_unicode(choice[1]) 214 215 self.index = index 216 self.serialization = serialization 215 217 216 218 def __unicode__(self): 217 return u'<label>%s %s</label>' % (self.tag (), self.choice_label)219 return u'<label>%s %s</label>' % (self.tag, self.choice_label) 218 220 219 221 def is_checked(self): 220 222 return self.value == self.choice_value … … 225 227 final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value) 226 228 if self.is_checked(): 227 229 final_attrs['checked'] = 'checked' 228 return u'<input%s />' % flatatt(final_attrs)230 return u'<input%s%s' % (flatatt(final_attrs),end_empty_element(u'input',self.serialization)) 229 231 230 232 class RadioFieldRenderer(StrAndUnicode): 231 233 "An object used by RadioSelect to enable customization of radio widgets." 232 def __init__(self, name, value, attrs, choices ):234 def __init__(self, name, value, attrs, choices, serialization=SERIALIZATION_DEFAULT): 233 235 self.name, self.value, self.attrs = name, value, attrs 234 236 self.choices = choices 237 self.serialization = serialization; 235 238 236 239 def __iter__(self): 237 240 for i, choice in enumerate(self.choices): … … 239 242 240 243 def __getitem__(self, idx): 241 244 choice = self.choices[idx] # Let the IndexError propogate 242 return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx )245 return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx, self.serialization) 243 246 244 247 def __unicode__(self): 245 248 "Outputs a <ul> for this set of radio fields." 246 249 return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % w for w in self]) 247 250 248 251 class RadioSelect(Select): 249 def render(self, name, value, attrs=None, choices=() ):252 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 250 253 "Returns a RadioFieldRenderer instance rather than a Unicode string." 251 254 if value is None: value = '' 252 255 str_value = smart_unicode(value) # Normalize to string. 253 256 attrs = attrs or {} 254 return RadioFieldRenderer(name, str_value, attrs, list(chain(self.choices, choices)) )257 return RadioFieldRenderer(name, str_value, attrs, list(chain(self.choices, choices)), serialization) 255 258 256 259 def id_for_label(self, id_): 257 260 # RadioSelect is represented by multiple <input type="radio"> fields, … … 264 267 id_for_label = classmethod(id_for_label) 265 268 266 269 class CheckboxSelectMultiple(SelectMultiple): 267 def render(self, name, value, attrs=None, choices=() ):270 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 268 271 if value is None: value = [] 269 272 has_id = attrs and attrs.has_key('id') 270 273 final_attrs = self.build_attrs(attrs, name=name) … … 277 280 final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i)) 278 281 cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) 279 282 option_value = smart_unicode(option_value) 280 rendered_cb = cb.render(name, option_value )283 rendered_cb = cb.render(name, option_value, serialization=serialization) 281 284 output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(smart_unicode(option_label)))) 282 285 output.append(u'</ul>') 283 286 return u'\n'.join(output) … … 311 314 self.widgets = [isinstance(w, type) and w() or w for w in widgets] 312 315 super(MultiWidget, self).__init__(attrs) 313 316 314 def render(self, name, value, attrs=None ):317 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 315 318 # value is a list of values, each corresponding to a widget 316 319 # in self.widgets. 317 320 if not isinstance(value, list): … … 322 325 widget_value = value[i] 323 326 except KeyError: 324 327 widget_value = None 325 output.append(widget.render(name + '_%s' % i, widget_value, attrs ))328 output.append(widget.render(name + '_%s' % i, widget_value, attrs, serialization)) 326 329 return self.format_output(output) 327 330 328 331 def value_from_datadict(self, data, name):