Changeset 4159
- Timestamp:
- 12/04/06 15:12:29 (3 years ago)
- Files:
-
- django/branches/multiple-db-support/AUTHORS (modified) (1 diff)
- django/branches/multiple-db-support/django/conf/project_template/urls.py (modified) (1 diff)
- django/branches/multiple-db-support/django/contrib/sitemaps/templates/sitemap_index.xml (modified) (1 diff)
- django/branches/multiple-db-support/django/core/handlers/base.py (modified) (1 diff)
- django/branches/multiple-db-support/django/core/handlers/wsgi.py (modified) (2 diffs)
- django/branches/multiple-db-support/django/db/models/fields/__init__.py (modified) (3 diffs)
- django/branches/multiple-db-support/django/http/__init__.py (modified) (1 diff)
- django/branches/multiple-db-support/django/newforms/fields.py (modified) (5 diffs)
- django/branches/multiple-db-support/django/newforms/forms.py (modified) (9 diffs)
- django/branches/multiple-db-support/django/newforms/__init__.py (modified) (1 diff)
- django/branches/multiple-db-support/django/newforms/models.py (copied) (copied from django/trunk/django/newforms/models.py)
- django/branches/multiple-db-support/django/newforms/widgets.py (modified) (9 diffs)
- django/branches/multiple-db-support/django/views/generic/list_detail.py (modified) (1 diff)
- django/branches/multiple-db-support/docs/sessions.txt (modified) (1 diff)
- django/branches/multiple-db-support/docs/testing.txt (modified) (1 diff)
- django/branches/multiple-db-support/setup.py (modified) (1 diff)
- django/branches/multiple-db-support/tests/regressiontests/forms/tests.py (modified) (33 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/multiple-db-support/AUTHORS
r4158 r4159 152 152 sopel 153 153 Thomas Steinacher <tom@eggdrop.ch> 154 nowell strite 154 155 Radek Švarz <http://www.svarz.cz/translate/> 155 156 Swaroop C H <http://www.swaroopch.info> django/branches/multiple-db-support/django/conf/project_template/urls.py
r2809 r4159 3 3 urlpatterns = patterns('', 4 4 # Example: 5 # (r'^{{ project_name }}/', include('{{ project_name }}. apps.foo.urls.foo')),5 # (r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')), 6 6 7 7 # Uncomment this for admin: django/branches/multiple-db-support/django/contrib/sitemaps/templates/sitemap_index.xml
r4158 r4159 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap index/0.9">2 <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> 3 3 {% for location in sitemaps %}<sitemap><loc>{{ location|escape }}</loc></sitemap>{% endfor %} 4 4 </sitemapindex> django/branches/multiple-db-support/django/core/handlers/base.py
r4156 r4159 85 85 # Complain if the view returned None (a common error). 86 86 if response is None: 87 raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, callback.func_name) 87 try: 88 view_name = callback.func_name # If it's a function 89 except AttributeError: 90 view_name = callback.__class__.__name__ + '.__call__' # If it's a class 91 raise ValueError, "The view %s.%s didn't return an HttpResponse object." % (callback.__module__, view_name) 88 92 89 93 return response django/branches/multiple-db-support/django/core/handlers/wsgi.py
r4158 r4159 63 63 """ 64 64 if not size: 65 return copyfileobj(fsrc, fdst, length)65 return 66 66 while size > 0: 67 67 buf = fsrc.read(min(length, size)) … … 158 158 except AttributeError: 159 159 buf = StringIO() 160 # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd) 161 content_length = int(self.environ.get('CONTENT_LENGTH', 0)) 160 try: 161 # CONTENT_LENGTH might be absent if POST doesn't have content at all (lighttpd) 162 content_length = int(self.environ.get('CONTENT_LENGTH', 0)) 163 except ValueError: # if CONTENT_LENGTH was empty string or not an integer 164 content_length = 0 162 165 safe_copyfileobj(self.environ['wsgi.input'], buf, size=content_length) 163 166 self._raw_post_data = buf.getvalue() django/branches/multiple-db-support/django/db/models/fields/__init__.py
r4157 r4159 458 458 def get_db_prep_save(self, value): 459 459 # Casts dates into string format for entry into database. 460 if isinstance(value, datetime.datetime): 461 value = value.date().strftime('%Y-%m-%d') 462 elif isinstance(value, datetime.date): 460 if value is not None: 463 461 value = value.strftime('%Y-%m-%d') 464 462 return Field.get_db_prep_save(self, value) … … 490 488 def pre_save(self, model_instance, add): 491 489 value = super(DateField, self).pre_save(model_instance, add) 492 if isinstance(value, datetime.datetime):490 if value is not None: 493 491 # MySQL will throw a warning if microseconds are given, because it 494 492 # doesn't support microseconds. … … 502 500 if value is not None: 503 501 value = str(value) 504 elif isinstance(value, datetime.date):505 # MySQL will throw a warning if microseconds are given, because it506 # doesn't support microseconds.507 if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):508 value = datetime.datetime(value.year, value.month, value.day, microsecond=0)509 value = str(value)510 511 502 return Field.get_db_prep_save(self, value) 512 503 django/branches/multiple-db-support/django/http/__init__.py
r4139 r4159 209 209 self.cookies[key]['path'] = path 210 210 if domain is not None: 211 self.cookies[key]['domain'] = path211 self.cookies[key]['domain'] = domain 212 212 self.cookies[key]['expires'] = 0 213 213 self.cookies[key]['max-age'] = 0 django/branches/multiple-db-support/django/newforms/fields.py
r4158 r4159 77 77 """ 78 78 super(IntegerField, self).clean(value) 79 if not self.required and value in EMPTY_VALUES: 80 return u'' 79 81 try: 80 82 return int(value) … … 171 173 if value in EMPTY_VALUES: value = u'' 172 174 value = smart_unicode(value) 175 if not self.required and value == u'': 176 return value 173 177 if not self.regex.search(value): 174 178 raise ValidationError(self.error_message) … … 247 251 if value in EMPTY_VALUES: value = u'' 248 252 value = smart_unicode(value) 253 if not self.required and value == u'': 254 return value 249 255 valid_values = set([str(k) for k, v in self.choices]) 250 256 if value not in valid_values: … … 260 266 Validates that the input is a list or tuple. 261 267 """ 268 if self.required and not value: 269 raise ValidationError(u'This field is required.') 270 elif not self.required and not value: 271 return [] 262 272 if not isinstance(value, (list, tuple)): 263 273 raise ValidationError(u'Enter a list of values.') 264 if self.required and not value:265 raise ValidationError(u'This field is required.')266 274 new_value = [] 267 275 for val in value: … … 278 286 def __init__(self, fields=(), required=True, widget=None): 279 287 Field.__init__(self, required, widget) 288 # Set 'required' to False on the individual fields, because the 289 # required validation will be handled by ComboField, not by those 290 # individual fields. 291 for f in fields: 292 f.required = False 280 293 self.fields = fields 281 294 django/branches/multiple-db-support/django/newforms/forms.py
r4158 r4159 4 4 5 5 from django.utils.datastructures import SortedDict 6 from django.utils.html import escape 6 7 from fields import Field 7 from widgets import TextInput, Textarea 8 from widgets import TextInput, Textarea, HiddenInput 8 9 from util import ErrorDict, ErrorList, ValidationError 9 10 … … 37 38 38 39 def __init__(self, data=None, auto_id=False): # TODO: prefix stuff 40 self.ignore_errors = data is None 39 41 self.data = data or {} 40 42 self.auto_id = auto_id … … 57 59 return BoundField(self, field, name) 58 60 59 def clean(self): 60 if self.__errors is None: 61 self.full_clean() 62 return self.clean_data 63 64 def errors(self): 61 def _errors(self): 65 62 "Returns an ErrorDict for self.data" 66 63 if self.__errors is None: 67 64 self.full_clean() 68 65 return self.__errors 66 errors = property(_errors) 69 67 70 68 def is_valid(self): 71 69 """ 72 Returns True if the form has no errors. Otherwise, False. This exists 73 solely for convenience, so client code can use positive logic rather 74 than confusing negative logic ("if not form.errors()"). 75 """ 76 return not bool(self.errors()) 70 Returns True if the form has no errors. Otherwise, False. If errors are 71 being ignored, returns False. 72 """ 73 return not self.ignore_errors and not bool(self.errors) 77 74 78 75 def as_table(self): 79 76 "Returns this form rendered as HTML <tr>s -- excluding the <table></table>." 80 return 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()]) 77 output = [] 78 if self.errors.get(NON_FIELD_ERRORS): 79 # Errors not corresponding to a particular field are displayed at the top. 80 output.append(u'<tr><td colspan="2">%s</td></tr>' % self.non_field_errors()) 81 for name, field in self.fields.items(): 82 bf = BoundField(self, field, name) 83 if bf.is_hidden: 84 if bf.errors: 85 new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors]) 86 output.append(u'<tr><td colspan="2">%s</td></tr>' % new_errors) 87 output.append(str(bf)) 88 else: 89 if bf.errors: 90 output.append(u'<tr><td colspan="2">%s</td></tr>' % bf.errors) 91 output.append(u'<tr><td>%s</td><td>%s</td></tr>' % (bf.label_tag(escape(bf.verbose_name+':')), bf)) 92 return u'\n'.join(output) 81 93 82 94 def as_ul(self): 83 95 "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>." 84 return u'\n'.join(['<li>%s: %s</li>' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()])85 86 def as_table_with_errors(self):87 "Returns this form rendered as HTML <tr>s, with errors."88 96 output = [] 89 if self.errors ().get(NON_FIELD_ERRORS):97 if self.errors.get(NON_FIELD_ERRORS): 90 98 # Errors not corresponding to a particular field are displayed at the top. 91 output.append( '<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]]))99 output.append(u'<li>%s</li>' % self.non_field_errors()) 92 100 for name, field in self.fields.items(): 93 101 bf = BoundField(self, field, name) 94 if bf.errors: 95 output.append('<tr><td colspan="2"><ul>%s</ul></td></tr>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors])) 96 output.append('<tr><td>%s:</td><td>%s</td></tr>' % (pretty_name(name), bf)) 102 if bf.is_hidden: 103 if bf.errors: 104 new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors]) 105 output.append(u'<li>%s</li>' % new_errors) 106 output.append(str(bf)) 107 else: 108 output.append(u'<li>%s%s %s</li>' % (bf.errors, bf.label_tag(escape(bf.verbose_name+':')), bf)) 97 109 return u'\n'.join(output) 98 110 99 def as_ul_with_errors(self): 100 "Returns this form rendered as HTML <li>s, with errors." 101 output = [] 102 if self.errors().get(NON_FIELD_ERRORS): 103 # Errors not corresponding to a particular field are displayed at the top. 104 output.append('<li><ul>%s</ul></li>' % '\n'.join(['<li>%s</li>' % e for e in self.errors()[NON_FIELD_ERRORS]])) 105 for name, field in self.fields.items(): 106 bf = BoundField(self, field, name) 107 line = '<li>' 108 if bf.errors: 109 line += '<ul>%s</ul>' % '\n'.join(['<li>%s</li>' % e for e in bf.errors]) 110 line += '%s: %s</li>' % (pretty_name(name), bf) 111 output.append(line) 112 return u'\n'.join(output) 111 def non_field_errors(self): 112 """ 113 Returns an ErrorList of errors that aren't associated with a particular 114 field -- i.e., from Form.clean(). Returns an empty ErrorList if there 115 are none. 116 """ 117 return self.errors.get(NON_FIELD_ERRORS, ErrorList()) 113 118 114 119 def full_clean(self): … … 118 123 self.clean_data = {} 119 124 errors = ErrorDict() 120 for name, field in self.fields.items(): 121 value = self.data.get(name, None) 125 if self.ignore_errors: # Stop further processing. 126 self.__errors = errors 127 return 128 for name, field in self.fields.items(): 129 # value_from_datadict() gets the data from the dictionary. 130 # Each widget type knows how to retrieve its own data, because some 131 # widgets split data over several HTML fields. 132 value = field.widget.value_from_datadict(self.data, name) 122 133 try: 123 134 value = field.clean(value) … … 139 150 """ 140 151 Hook for doing any extra form-wide cleaning after Field.clean() been 141 called on every field. 152 called on every field. Any ValidationError raised by this method will 153 not be associated with a particular field; it will have a special-case 154 association with the field named '__all__'. 142 155 """ 143 156 return self.clean_data … … 154 167 # Use the 'widget' attribute on the field to determine which type 155 168 # of HTML widget to use. 156 return self.as_widget(self._field.widget) 169 value = self.as_widget(self._field.widget) 170 if not isinstance(value, basestring): 171 # Some Widget render() methods -- notably RadioSelect -- return a 172 # "special" object rather than a string. Call the __str__() on that 173 # object to get its rendered value. 174 value = value.__str__() 175 return value 157 176 158 177 def _errors(self): … … 162 181 """ 163 182 try: 164 return self._form.errors ()[self._name]183 return self._form.errors[self._name] 165 184 except KeyError: 166 185 return ErrorList() … … 170 189 attrs = attrs or {} 171 190 auto_id = self.auto_id 172 if not attrs.has_key('id') and not widget.attrs.has_key('id') and auto_id:191 if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'): 173 192 attrs['id'] = auto_id 174 return widget.render(self._name, self. _form.data.get(self._name, None), attrs=attrs)193 return widget.render(self._name, self.data, attrs=attrs) 175 194 176 195 def as_text(self, attrs=None): … … 183 202 "Returns a string of HTML for representing this as a <textarea>." 184 203 return self.as_widget(Textarea(), attrs) 204 205 def as_hidden(self, attrs=None): 206 """ 207 Returns a string of HTML for representing this as an <input type="hidden">. 208 """ 209 return self.as_widget(HiddenInput(), attrs) 210 211 def _data(self): 212 "Returns the data for this BoundField, or None if it wasn't given." 213 return self._form.data.get(self._name, None) 214 data = property(_data) 215 216 def _verbose_name(self): 217 return pretty_name(self._name) 218 verbose_name = property(_verbose_name) 219 220 def label_tag(self, contents=None): 221 """ 222 Wraps the given contents in a <label>, if the field has an ID attribute. 223 Does not HTML-escape the contents. If contents aren't given, uses the 224 field's HTML-escaped verbose_name. 225 """ 226 contents = contents or escape(self.verbose_name) 227 widget = self._field.widget 228 id_ = widget.attrs.get('id') or self.auto_id 229 if id_: 230 contents = '<label for="%s">%s</label>' % (widget.id_for_label(id_), contents) 231 return contents 232 233 def _is_hidden(self): 234 "Returns True if this BoundField's widget is hidden." 235 return self._field.widget.is_hidden 236 is_hidden = property(_is_hidden) 185 237 186 238 def _auto_id(self): django/branches/multiple-db-support/django/newforms/__init__.py
r4156 r4159 15 15 from fields import * 16 16 from forms import Form 17 18 ########################## 19 # DATABASE API SHORTCUTS # 20 ########################## 21 22 def form_for_model(model): 23 "Returns a Form instance for the given Django model class." 24 raise NotImplementedError 25 26 def form_for_fields(field_list): 27 "Returns a Form instance for the given list of Django database field instances." 28 raise NotImplementedError 17 from models import * django/branches/multiple-db-support/django/newforms/widgets.py
r4158 r4159 6 6 'Widget', 'TextInput', 'PasswordInput', 'HiddenInput', 'FileInput', 7 7 'Textarea', 'CheckboxInput', 8 'Select', 'SelectMultiple', 'RadioSelect', 8 'Select', 'SelectMultiple', 'RadioSelect', 'CheckboxSelectMultiple', 9 9 ) 10 10 … … 24 24 class Widget(object): 25 25 requires_data_list = False # Determines whether render()'s 'value' argument should be a list. 26 is_hidden = False # Determines whether this corresponds to an <input type="hidden">. 27 26 28 def __init__(self, attrs=None): 27 29 self.attrs = attrs or {} … … 31 33 32 34 def build_attrs(self, extra_attrs=None, **kwargs): 35 "Helper function for building an attribute dictionary." 33 36 attrs = dict(self.attrs, **kwargs) 34 37 if extra_attrs: 35 38 attrs.update(extra_attrs) 36 39 return attrs 40 41 def value_from_datadict(self, data, name): 42 """ 43 Given a dictionary of data and this widget's name, returns the value 44 of this widget. Returns None if it's not provided. 45 """ 46 return data.get(name, None) 47 48 def id_for_label(self, id_): 49 """ 50 Returns the HTML ID attribute of this Widget for use by a <label>, 51 given the ID of the field. Returns None if no ID is available. 52 53 This hook is necessary because some widgets have multiple HTML 54 elements and, thus, multiple IDs. In that case, this method should 55 return an ID value that corresponds to the first ID in the widget's 56 tags. 57 """ 58 return id_ 59 id_for_label = classmethod(id_for_label) 37 60 38 61 class Input(Widget): … … 56 79 class HiddenInput(Input): 57 80 input_type = 'hidden' 81 is_hidden = True 58 82 59 83 class FileInput(Input): … … 68 92 69 93 class CheckboxInput(Widget): 94 def __init__(self, attrs=None, check_test=bool): 95 # check_test is a callable that takes a value and returns True 96 # if the checkbox should be checked for that value. 97 self.attrs = attrs or {} 98 self.check_test = check_test 99 70 100 def render(self, name, value, attrs=None): 71 101 final_attrs = self.build_attrs(attrs, type='checkbox', name=name) 72 if value: final_attrs['checked'] = 'checked' 102 try: 103 result = self.check_test(value) 104 except: # Silently catch exceptions 105 result = False 106 if result: 107 final_attrs['checked'] = 'checked' 108 if value not in ('', True, False, None): 109 final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty. 73 110 return u'<input%s />' % flatatt(final_attrs) 74 111 … … 112 149 class RadioInput(object): 113 150 "An object used by RadioFieldRenderer that represents a single <input type='radio'>." 114 def __init__(self, name, value, attrs, choice ):151 def __init__(self, name, value, attrs, choice, index): 115 152 self.name, self.value = name, value 116 self.attrs = attrs or {}153 self.attrs = attrs 117 154 self.choice_value, self.choice_label = choice 155 self.index = index 118 156 119 157 def __str__(self): … … 124 162 125 163 def tag(self): 164 if self.attrs.has_key('id'): 165 self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) 126 166 final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value) 127 167 if self.is_checked(): … … 136 176 137 177 def __iter__(self): 138 for choice in self.choices:139 yield RadioInput(self.name, self.value, self.attrs , choice)178 for i, choice in enumerate(self.choices): 179 yield RadioInput(self.name, self.value, self.attrs.copy(), choice, i) 140 180 141 181 def __str__(self): … … 148 188 if value is None: value = '' 149 189 str_value = smart_unicode(value) # Normalize to string. 190 attrs = attrs or {} 150 191 return RadioFieldRenderer(name, str_value, attrs, list(chain(self.choices, choices))) 151 192 152 class CheckboxSelectMultiple(Widget): 153 pass 193 def id_for_label(self, id_): 194 # RadioSelect is represented by multiple <input type="radio"> fields, 195 # each of which has a distinct ID. The IDs are made distinct by a "_X" 196 # suffix, where X is the zero-based index of the radio field. Thus, 197 # the label for a RadioSelect should reference the first one ('_0'). 198 if id_: 199 id_ += '_0' 200 return id_ 201 id_for_label = classmethod(id_for_label) 202 203 class CheckboxSelectMultiple(SelectMultiple): 204 def render(self, name, value, attrs=None, choices=()): 205 if value is None: value = [] 206 final_attrs = self.build_attrs(attrs, name=name) 207 output = [u'<ul>'] 208 str_values = set([smart_unicode(v) for v in value]) # Normalize to strings. 209 cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) 210 for option_value, option_label in chain(self.choices, choices): 211 option_value = smart_unicode(option_value) 212 rendered_cb = cb.render(name, option_value) 213 output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(smart_unicode(option_label)))) 214 output.append(u'</ul>') 215 return u'\n'.join(output) 216 217 def id_for_label(self, id_): 218 # See the comment for RadioSelect.id_for_label() 219 if id_: 220 id_ += '_0' 221 return id_ 222 id_for_label = classmethod(id_for_label) django/branches/multiple-db-support/django/views/generic/list_detail.py
r3071 r4159 85 85 mimetype=None): 86 86 """ 87 Generic list of objects.87 Generic detail of an object. 88 88 89 89 Templates: ``<app_label>/<model_name>_detail.html`` django/branches/multiple-db-support/docs/sessions.txt
r3581 r4159 142 142 143 143 def login(request): 144 if request. POST:144 if request.method == 'POST': 145 145 if request.session.test_cookie_worked(): 146 146 request.session.delete_test_cookie() django/branches/multiple-db-support/docs/testing.txt
r4158 r4159 134 134 135 135 For developers new to testing, however, this choice can seem 136 confusing, so here are a few key differences to help you decide w eather136 confusing, so here are a few key differences to help you decide whether 137 137 doctests or unit tests are right for you. 138 138 django/branches/multiple-db-support/setup.py
r4155 r4159 12 12 # an easy way to do this. 13 13 packages, data_files = [], [] 14 root_dir = os.path.join(os.path.dirname(__file__), 'django') 15 for dirpath, dirnames, filenames in os.walk(root_dir): 14 root_dir = os.path.dirname(__file__) 15 len_root_dir = len(root_dir) 16 django_dir = os.path.join(root_dir, 'django') 17 18 for dirpath, dirnames, filenames in os.walk(django_dir): 16 19 # Ignore dirnames that start with '.' 17 20 for i, dirname in enumerate(dirnames): 18 21 if dirname.startswith('.'): del dirnames[i] 19 22 if '__init__.py' in filenames: 20 packages.append(dirpath.replace('/', '.')) 23 package = dirpath[len_root_dir:].lstrip('/').replace('/', '.') 24 packages.append(package) 21 25 else: 22 26 data_files.append((dirpath, [os.path.join(dirpath, f) for f in filenames])) django/branches/multiple-db-support/tests/regressiontests/forms/tests.py
r4158 r4159 4 4 >>> import datetime 5 5 >>> import re 6 7 ########### 8 # Widgets # 9 ########### 10 11 Each Widget class corresponds to an HTML form widget. A Widget knows how to 12 render itself, given a field name and some data. Widgets don't perform 13 validation. 6 14 7 15 # TextInput Widget ############################################################ … … 157 165 >>> w.render('is_cool', '') 158 166 u'<input type="checkbox" name="is_cool" />' 167 >>> w.render('is_cool', None) 168 u'<input type="checkbox" name="is_cool" />' 159 169 >>> w.render('is_cool', False) 160 170 u'<input type="checkbox" name="is_cool" />' 161 171 >>> w.render('is_cool', True) 162 172 u'<input checked="checked" type="checkbox" name="is_cool" />' 173 174 Using any value that's not in ('', None, False, True) will check the checkbox 175 and set the 'value' attribute. 176 >>> w.render('is_cool', 'foo') 177 u'<input checked="checked" type="checkbox" name="is_cool" value="foo" />' 178 163 179 >>> w.render('is_cool', False, attrs={'class': 'pretty'}) 164 180 u'<input type="checkbox" name="is_cool" class="pretty" />' … … 173 189 >>> w.render('is_cool', '', attrs={'class': 'special'}) 174 190 u'<input type="checkbox" class="special" name="is_cool" />' 191 192 You can pass 'check_test' to the constructor. This is a callable that takes the 193 value and returns True if the box should be checked. 194 >>> w = CheckboxInput(check_test=lambda value: value.startswith('hello')) 195 >>> w.render('greeting', '') 196 u'<input type="checkbox" name="greeting" />' 197 >>> w.render('greeting', 'hello') 198 u'<input checked="checked" type="checkbox" name="greeting" value="hello" />' 199 >>> w.render('greeting', 'hello there') 200 u'<input checked="checked" type="checkbox" name="greeting" value="hello there" />' 201 >>> w.render('greeting', 'hello & goodbye') 202 u'<input checked="checked" type="checkbox" name="greeting" value="hello & goodbye" />' 203 204 A subtlety: If the 'check_test' argument cannot handle a value and raises any 205 exception during its __call__, then the exception will be swallowed and the box 206 will not be checked. In this example, the 'check_test' assumes the value has a 207 startswith() method, which fails for the values True, False and None. 208 >>> w.render('greeting', True) 209 u'<input type="checkbox" name="greeting" />' 210 >>> w.render('greeting', False) 211 u'<input type="checkbox" name="greeting" />' 212 >>> w.render('greeting', None) 213 u'<input type="checkbox" name="greeting" />' 175 214 176 215 # Select Widget ############################################################### … … 476 515 beatle J R Ringo False 477 516 517 # CheckboxSelectMultiple Widget ############################################### 518 519 >>> w = CheckboxSelectMultiple() 520 >>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 521 <ul> 522 <li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 523 <li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 524 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 525 <li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 526 </ul> 527 >>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 528 <ul> 529 <li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 530 <li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li> 531 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 532 <li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 533 </ul> 534 >>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 535 <ul> 536 <li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 537 <li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li> 538 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 539 <li><label><input checked="checked" type="checkbox" name="beatles" value="R" /> Ringo</label></li> 540 </ul> 541 542 If the value is None, none of the options are selected: 543 >>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 544 <ul> 545 <li><label><input type="checkbox" name="beatles" value="J" /> John</label></li> 546 <li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 547 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 548 <li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 549 </ul> 550 551 If the value corresponds to a label (but not to an option value), none of the options are selected: 552 >>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 553 <ul> 554 <li><label><input type="checkbox" name="beatles" value="J" /> John</label></li> 555 <li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 556 <li><label><input type="checkbox" name="beatles" value="G" /> George</label></li> 557 <li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 558 </ul> 559 560 If multiple values are given, but some of them are not valid, the valid ones are selected: 561 >>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))) 562 <ul> 563 <li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li> 564 <li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li> 565 <li><label><input checked="checked" type="checkbox" name="beatles" value="G" /> George</label></li> 566 <li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li> 567 </ul> 568 569 The value is compared to its str(): 570 >>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]) 571 <ul> 572 <li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 573 <li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 574 <li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 575 </ul> 576 >>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]) 577 <ul> 578 <li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 579 <li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 580 <li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 581 </ul> 582 >>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]) 583 <ul> 584 <li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 585 <li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 586 <li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 587 </ul> 588 589 The 'choices' argument can be any iterable: 590 >>> def get_choices(): 591 ... for i in range(5): 592 ... yield (i, i) 593 >>> print w.render('nums', [2], choices=get_choices()) 594 <ul> 595 <li><label><input type="checkbox" name="nums" value="0" /> 0</label></li> 596 <li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 597 <li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 598 <li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 599 <li><label><input type="checkbox" name="nums" value="4" /> 4</label></li> 600 </ul> 601 602 You can also pass 'choices' to the constructor: 603 >>> w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)]) 604 >>> print w.render('nums', [2]) 605 <ul> 606 <li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 607 <li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 608 <li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 609 </ul> 610 611 If 'choices' is passed to both the constructor and render(), then they'll both be in the output: 612 >>> print w.render('nums', [2], choices=[(4, 4), (5, 5)]) 613 <ul> 614 <li><label><input type="checkbox" name="nums" value="1" /> 1</label></li> 615 <li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li> 616 <li><label><input type="checkbox" name="nums" value="3" /> 3</label></li> 617 <li><label><input type="checkbox" name="nums" value="4" /> 4</label></li> 618 <li><label><input type="checkbox" name="nums" value="5" /> 5</label></li> 619 </ul> 620 621 >>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) 622 u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>' 623 624 ########## 625 # Fields # 626 ########## 627 628 Each Field class does some sort of validation. Each Field has a clean() method, 629 which either raises django.newforms.ValidationError or returns the "clean" 630 data -- usually a Unicode object, but, in some rare cases, a list. 631 632 Each Field's __init__() takes at least these parameters: 633 required -- Boolean that specifies whether the field is required. 634 True by default. 635 widget -- A Widget class, or instance of a Widget class, that should be 636 used for this Field when displaying it. Each Field has a default 637 Widget that it'll use if you don't specify this. In most cases, 638 the default widget is TextInput. 639 640 Other than that, the Field subclasses have class-specific options for 641 __init__(). For example, CharField has a max_length option. 642 478 643 # CharField ################################################################### 644 645 >>> f = CharField() 646 >>> f.clean(1) 647 u'1' 648 >>> f.clean('hello') 649 u'hello' 650 >>> f.clean(None) 651 Traceback (most recent call last): 652 ... 653 ValidationError: [u'This field is required.'] 654 >>> f.clean('') 655 Traceback (most recent call last): 656 ... 657 ValidationError: [u'This field is required.'] 658 >>> f.clean([1, 2, 3]) 659 u'[1, 2, 3]' 479 660 480 661 >>> f = CharField(required=False) … … 485 666 >>> f.clean(None) 486 667 u'' 668 >>> f.clean('') 669 u'' 487 670 >>> f.clean([1, 2, 3]) 488 671 u'[1, 2, 3]' … … 490 673 CharField accepts an optional max_length parameter: 491 674 >>> f = CharField(max_length=10, required=False) 492 >>> f.clean('')493 u''494 675 >>> f.clean('12345') 495 676 u'12345' … … 519 700 520 701 >>> f = IntegerField() 702 >>> f.clean('') 703 Traceback (most recent call last): 704 ... 705 ValidationError: [u'This field is required.'] 706 >>> f.clean(None) 707 Traceback (most recent call last): 708 ... 709 ValidationError: [u'This field is required.'] 710 >>> f.clean('1') 711 1 712 >>> isinstance(f.clean('1'), int) 713 True 714 >>> f.clean('23') 715 23 716 >>> f.clean('a') 717 Traceback (most recent call last): 718 ... 719 ValidationError: [u'Enter a whole number.'] 720 >>> f.clean('1 ') 721 1 722 >>> f.clean(' 1') 723 1 724 >>> f.clean(' 1 ') 725 1 726 >>> f.clean('1a') 727 Traceback (most recent call last): 728 ... 729 ValidationError: [u'Enter a whole number.'] 730 731 >>> f = IntegerField(required=False) 732 >>> f.clean('') 733 u'' 734 >>> f.clean(None) 735 u'' 521 736 >>> f.clean('1') 522 737 1 … … 682 897 ValidationError: [u'Enter a valid date/time.'] 683 898 899 >>> f = DateTimeField(required=False) 900 >>> f.clean(None) 901 >>> repr(f.clean(None)) 902 'None' 903 >>> f.clean('') 904 >>> repr(f.clean('')) 905 'None' 906 684 907 # RegexField ################################################################## 685 908 … … 701 924 ... 702 925 ValidationError: [u'Enter a valid value.'] 926 >>> f.clean('') 927 Traceback (most recent call last): 928 ... 929 ValidationError: [u'This field is required.'] 930 931 >>> f = RegexField('^\d[A-F]\d$', required=False) 932 >>> f.clean('2A2') 933 u'2A2' 934 >>> f.clean('3F3') 935 u'3F3' 936 >>> f.clean('3G3') 937 Traceback (most recent call last): 938 ... 939 ValidationError: [u'Enter a valid value.'] 940 >>> f.clean('') 941 u'' 703 942 704 943 Alternatively, RegexField can take a compiled regular expression: … … 737 976 738 977 >>> f = EmailField() 978 >>> f.clean('') 979 Traceback (most recent call last): 980 ... 981 ValidationError: [u'This field is required.'] 982 >>> f.clean(None) 983 Traceback (most recent call last): 984 ... 985 ValidationError: [u'This field is required.'] 739 986 >>> f.clean('person@example.com') 740 987 u'person@example.com' … … 752 999 ValidationError: [u'Enter a valid e-mail address.'] 753 1000 1001 >>> f = EmailField(required=False) 1002 >>> f.clean('') 1003 u'' 1004 >>> f.clean(None) 1005 u'' 1006 >>> f.clean('person@example.com') 1007 u'person@example.com' 1008 >>> f.clean('foo') 1009 Traceback (most recent call last): 1010 ... 1011 ValidationError: [u'Enter a valid e-mail address.'] 1012 >>> f.clean('foo@') 1013 Traceback (most recent call last): 1014 ... 1015 ValidationError: [u'Enter a valid e-mail address.'] 1016 >>> f.clean('foo@bar') 1017 Traceback (most recent call last): 1018 ... 1019 ValidationError: [u'Enter a valid e-mail address.'] 1020 754 1021 # URLField ################################################################## 755 1022 756 1023 >>> f = URLField() 1024 >>> f.clean('') 1025 Traceback (most recent call last): 1026 ... 1027 ValidationError: [u'This field is required.'] 1028 >>> f.clean(None) 1029 Traceback (most recent call last): 1030 ... 1031 ValidationError: [u'This field is required.'] 1032 >>> f.clean('http://example.com') 1033 u'http://example.com' 1034 >>> f.clean('http://www.example.com') 1035 u'http://www.example.com' 1036 >>> f.clean('foo') 1037 Traceback (most recent call last): 1038 ... 1039 ValidationError: [u'Enter a valid URL.'] 1040 >>> f.clean('example.com') 1041 Traceback (most recent call last): 1042 ... 1043 ValidationError: [u'Enter a valid URL.'] 1044 >>> f.clean('http://') 1045 Traceback (most recent call last): 1046 ... 1047 ValidationError: [u'Enter a valid URL.'] 1048 >>> f.clean('http://example') 1049 Traceback (most recent call last): 1050 ... 1051 ValidationError: [u'Enter a valid URL.'] 1052 >>> f.clean('http://example.') 1053 Traceback (most recent call last): 1054 ... 1055 ValidationError: [u'Enter a valid URL.'] 1056 >>> f.clean('http://.com') 1057 Traceback (most recent call last): 1058 ... 1059 ValidationError: [u'Enter a valid URL.'] 1060 1061 >>> f = URLField(required=False) 1062 >>> f.clean('') 1063 u'' 1064 >>> f.clean(None) 1065 u'' 757 1066 >>> f.clean('http://example.com') 758 1067 u'http://example.com' … … 805 1114 806 1115 >>> f = BooleanField() 1116 >>> f.clean('') 1117 Traceback (most recent call last): 1118 ... 1119 ValidationError: [u'This field is required.'] 1120 >>> f.clean(None) 1121 Traceback (most recent call last): 1122 ... 1123 ValidationError: [u'This field is required.'] 807 1124 >>> f.clean(True) 808 1125 True … … 816 1133 True 817 1134 1135 >>> f = BooleanField(required=False) 1136 >>> f.clean('') 1137 False 1138 >>> f.clean(None) 1139 False 1140 >>> f.clean(True) 1141 True 1142 >>> f.clean(False) 1143 False 1144 >>> f.clean(1) 1145 True 1146 >>> f.clean(0) 1147 False 1148 >>> f.clean('Django rocks') 1149 True 1150 818 1151 # ChoiceField ################################################################# 819 1152 820 1153 >>> f = ChoiceField(choices=[('1', '1'), ('2', '2')]) 1154 >>> f.clean('') 1155 Traceback (most recent call last): 1156 ... 1157 ValidationError: [u'This field is required.'] 1158 >>> f.clean(None) 1159 Traceback (most recent call last): 1160 ... 1161 ValidationError: [u'This field is required.'] 821 1162 >>> f.clean(1) 822 1163 u'1' 823 1164 >>> f.clean('1') 824 1165 u'1' 1166 >>> f.clean('3') 1167 Traceback (most recent call last): 1168 ... 1169 ValidationError: [u'Select a valid choice. 3 is not one of the available choices.'] 1170 1171 >>> f = ChoiceField(choices=[('1', '1'), ('2', '2')], required=False) 1172 >>> f.clean('') 1173 u'' 825 1174 >>> f.clean(None) 826 Traceback (most recent call last): 827 ... 828 ValidationError: [u'This field is required.'] 829 >>> f.clean('') 830 Traceback (most recent call last): 831 ... 832 ValidationError: [u'This field is required.'] 1175 u'' 1176 >>> f.clean(1) 1177 u'1' 1178 >>> f.clean('1') 1179 u'1' 833 1180 >>> f.clean('3') 834 1181 Traceback (most recent call last): … … 847 1194 848 1195 >>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')]) 1196 >>> f.clean('') 1197 Traceback (most recent call last): 1198 ... 1199 ValidationError: [u'This field is required.'] 1200 >>> f.clean(None) 1201 Traceback (most recent call last): 1202 ... 1203 ValidationError: [u'This field is required.'] 849 1204 >>> f.clean([1]) 850 1205 [u'1'] … … 874 1229 ValidationError: [u'Select a valid choice. 3 is not one of the available choices.'] 875 1230 1231 >>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')], required=False) 1232 >>> f.clean('') 1233 [] 1234 >>> f.clean(None) 1235 [] 1236 >>> f.clean([1]) 1237 [u'1'] 1238 >>> f.clean(['1']) 1239 [u'1'] 1240 >>> f.clean(['1', '2']) 1241 [u'1', u'2'] 1242 >>> f.clean([1, '2']) 1243 [u'1', u'2'] 1244 >>> f.clean((1, '2')) 1245 [u'1', u'2'] 1246 >>> f.clean('hello') 1247 Traceback (most recent call last): 1248 ... 1249 ValidationError: [u'Enter a list of values.'] 1250 >>> f.clean([]) 1251 [] 1252 >>> f.clean(()) 1253 [] 1254 >>> f.clean(['3']) 1255 Traceback (most recent call last): 1256 ... 1257 ValidationError: [u'Select a valid choice. 3 is not one of the available choices.'] 1258 876 1259 # ComboField ################################################################## 877 1260 878 1261 ComboField takes a list of fields that should be used to validate a value, 879 in that order :1262 in that order. 880 1263 >>> f = ComboField(fields=[CharField(max_length=20), EmailField()]) 881 1264 >>> f.clean('test@example.com') … … 898 1281 ValidationError: [u'This field is required.'] 899 1282 1283 >>> f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False) 1284 >>> f.clean('test@example.com') 1285 u'test@example.com' 1286 >>> f.clean('longemailaddress@example.com') 1287 Traceback (most recent call last): 1288 ... 1289 ValidationError: [u'Ensure this value has at most 20 characters.'] 1290 >>> f.clean('not an e-mail') 1291 Traceback (most recent call last): 1292 ... 1293 ValidationError: [u'Enter a valid e-mail address.'] 1294 >>> f.clean('') 1295 u'' 1296 >>> f.clean(None) 1297 u'' 1298 1299 ######### 1300 # Forms # 1301 ######### 1302 1303 A Form is a collection of Fields. It knows how to validate a set of data and it 1304 knows how to render itself in a couple of default ways (e.g., an HTML table). 1305 You can pass it data in __init__(), as a dictionary. 1306 900 1307 # Form ######################################################################## 901 1308 … … 904 1311 ... last_name = CharField() 905 1312 ... birthday = DateField() 1313 1314 Pass a dictionary to a Form's __init__(). 1315 >>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'}) 1316 >>> p.errors 1317 {} 1318 >>> p.is_valid() 1319 True 1320 >>> p.errors.as_ul() 1321 u'' 1322 >>> p.errors.as_text() 1323 u'' 1324 >>> p.clean_data 1325 {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} 1326 >>> print p['first_name'] 1327 <input type="text" name="first_name" value="John" /> 1328 >>> print p['last_name'] 1329 <input type="text" name="last_name" value="Lennon" /> 1330 >>> print p['birthday'] 1331 <input type="text" name="birthday" value="1940-10-9" /> 1332 >>> for boundfield in p: 1333 ... print boundfield 1334 <input type="text" name="first_name" value="John" /> 1335 <input type="text" name="last_name" value="Lennon" /> 1336 <input type="text" name="birthday" value="1940-10-9" /> 1337 >>> for boundfield in p: 1338 ... print boundfield.verbose_name, boundfield.data 1339 First name John 1340 Last name Lennon 1341 Birthday 1940-10-9 1342 >>> print p 1343 <tr><td>First name:</td><td><input type="text" name="first_name" value="John" /></td></tr> 1344 <tr><td>Last name:</td><td><input type="text" name="last_name" value="Lennon" /></td></tr> 1345 <tr><td>Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /></td></tr> 1346 1347 Empty dictionaries are valid, too. 1348 >>> p = Person({}) 1349 >>> p.errors 1350 {'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} 1351 >>> p.is_valid() 1352 False 1353 >>> print p 1354 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1355 <tr><td>First name:</td><td><input type="text" name="first_name" /></td></tr> 1356 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1357 <tr><td>Last name:</td><td><input type="text" name="last_name" /></td></tr> 1358 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1359 <tr><td>Birthday:</td><td><input type="text" name="birthday" /></td></tr> 1360 >>> print p.as_table() 1361 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1362 <tr><td>First name:</td><td><input type="text" name="first_name" /></td></tr> 1363 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1364 <tr><td>Last name:</td><td><input type="text" name="last_name" /></td></tr> 1365 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1366 <tr><td>Birthday:</td><td><input type="text" name="birthday" /></td></tr> 1367 >>> print p.as_ul() 1368 <li><ul class="errorlist"><li>This field is required.</li></ul>First name: <input type="text" name="first_name" /></li> 1369 <li><ul class="errorlist"><li>This field is required.</li></ul>Last name: <input type="text" name="last_name" /></li> 1370 <li><ul class="errorlist"><li>This field is required.</li></ul>Birthday: <input type="text" name="birthday" /></li> 1371 1372 If you don't pass any values to the Form's __init__(), or if you pass None, 1373 the Form won't do any validation. Form.errors will be an empty dictionary *but* 1374 Form.is_valid() will return False. 906 1375 >>> p = Person() 1376 >>> p.errors 1377 {} 1378 >>> p.is_valid() 1379 False 907 1380 >>> print p 908 1381 <tr><td>First name:</td><td><input type="text" name="first_name" /></td></tr> … … 917 1390 <li>Last name: <input type="text" name="last_name" /></li> 918 1391 <li>Birthday: <input type="text" name="birthday" /></li> 919 >>> print p.as_table_with_errors() 920 <tr><td colspan="2"><ul><li>This field is required.</li></ul></td></tr> 921 <tr><td>First name:</td><td><input type="text" name="first_name" /></td></tr> 922 <tr><td colspan="2"><ul><li>This field is required.</li></ul></td></tr> 923 <tr><td>Last name:</td><td><input type="text" name="last_name" /></td></tr> 924 <tr><td colspan="2"><ul><li>This field is required.</li></ul></td></tr> 925 <tr><td>Birthday:</td><td><input type="text" name="birthday" /></td></tr> 926 >>> print p.as_ul_with_errors() 927 <li><ul><li>This field is required.</li></ul>First name: <input type="text" name="first_name" /></li> 928 <li><ul><li>This field is required.</li></ul>Last name: <input type="text" name="last_name" /></li> 929 <li><ul><li>This field is required.</li></ul>Birthday: <input type="text" name="birthday" /></li> 930 931 >>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'}) 932 >>> p.errors() 933 {} 934 >>> p.is_valid() 935 True 936 >>> p.errors().as_ul() 937 u'' 938 >>> p.errors().as_text() 939 u'' 940 >>> p.clean() 941 {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} 942 >>> print p['first_name'] 943 <input type="text" name="first_name" value="John" /> 944 >>> print p['last_name'] 945 <input type="text" name="last_name" value="Lennon" /> 946 >>> print p['birthday'] 947 <input type="text" name="birthday" value="1940-10-9" /> 948 >>> for boundfield in p: 949 ... print boundfield 950 <input type="text" name="first_name" value="John" /> 951 <input type="text" name="last_name" value="Lennon" /> 952 <input type="text" name="birthday" value="1940-10-9" /> 953 >>> print p 954 <tr><td>First name:</td><td><input type="text" name="first_name" value="John" /></td></tr> 955 <tr><td>Last name:</td><td><input type="text" name="last_name" value="Lennon" /></td></tr> 956 <tr><td>Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /></td></tr> 1392 1393 Unicode values are handled properly. 1394 >>> p = Person({'first_name': u'John', 'last_name': u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111', 'birthday': '1940-10-9'}) 1395 >>> p.as_table() 1396 u'<tr><td>First name:</td><td><input type="text" name="first_name" value="John" /></td></tr>\n<tr><td>Last name:</td><td><input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /></td></tr>\n<tr><td>Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /></td></tr>' 1397 >>> p.as_ul() 1398 u'<li>First name: <input type="text" name="first_name" value="John" /></li>\n<li>Last name: <input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /></li>\n<li>Birthday: <input type="text" name="birthday" value="1940-10-9" /></li>' 957 1399 958 1400 >>> p = Person({'last_name': u'Lennon'}) 959 >>> p.errors ()1401 >>> p.errors 960 1402 {'first_name': [u'This field is required.'], 'birthday': [u'This field is required.']} 961 1403 >>> p.is_valid() 962 1404 False 963 >>> p.errors ().as_ul()1405 >>> p.errors.as_ul() 964 1406 u'<ul class="errorlist"><li>first_name<ul class="errorlist"><li>This field is required.</li></ul></li><li>birthday<ul class="errorlist"><li>This field is required.</li></ul></li></ul>' 965 >>> print p.errors ().as_text()1407 >>> print p.errors.as_text() 966 1408 * first_name 967 1409 * This field is required. 968 1410 * birthday 969 1411 * This field is required. 970 >>> p.clean ()971 >>> repr(p.clean ())1412 >>> p.clean_data 1413 >>> repr(p.clean_data) 972 1414 'None' 973 1415 >>> p['first_name'].errors … … 988 1430 "auto_id" tells the Form to add an "id" attribute to each form element. 989 1431 If it's a string that contains '%s', Django will use that as a format string 990 into which the field's name will be inserted. 1432 into which the field's name will be inserted. It will also put a <label> around 1433 the human-readable labels for a field. 991 1434 >>> p = Person(auto_id='id_%s') 992 1435 >>> print p.as_ul() 993 <li>First name: <input type="text" name="first_name" id="id_first_name" /></li> 994 <li>Last name: <input type="text" name="last_name" id="id_last_name" /></li> 995 <li>Birthday: <input type="text" name="birthday" id="id_birthday" /></li> 1436 <li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li> 1437 <li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li> 1438 <li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li> 1439 >>> print p.as_table() 1440 <tr><td><label for="id_first_name">First name:</label></td><td><input type="text" name="first_name" id="id_first_name" /></td></tr> 1441 <tr><td><label for="id_last_name">Last name:</label></td><td><input type="text" name="last_name" id="id_last_name" /></td></tr> 1442 <tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /></td></tr> 996 1443 997 1444 If auto_id is any True value whose str() does not contain '%s', the "id" … … 999 1446 >>> p = Person(auto_id=True) 1000 1447 >>> print p.as_ul() 1001 <li> First name:<input type="text" name="first_name" id="first_name" /></li>1002 <li> Last name:<input type="text" name="last_name" id="last_name" /></li>1003 <li> Birthday:<input type="text" name="birthday" id="birthday" /></li>1448 <li><label for="first_name">First name:</label> <input type="text" name="first_name" id="first_name" /></li> 1449 <li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li> 1450 <li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li> 1004 1451 1005 1452 If auto_id is any False value, an "id" attribute won't be output unless it … … 1012 1459 1013 1460 In this example, auto_id is False, but the "id" attribute for the "first_name" 1014 field is given. 1461 field is given. Also note that field gets a <label>, while the others don't. 1015 1462 >>> class PersonNew(Form): 1016 1463 ... first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'})) … … 1019 1466 >>> p = PersonNew(auto_id=False) 1020 1467 >>> print p.as_ul() 1021 <li> First name:<input type="text" id="first_name_id" name="first_name" /></li>1468 <li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li> 1022 1469 <li>Last name: <input type="text" name="last_name" /></li> 1023 1470 <li>Birthday: <input type="text" name="birthday" /></li> … … 1027 1474 >>> p = PersonNew(auto_id=True) 1028 1475 >>> print p.as_ul() 1029 <li> First name:<input type="text" id="first_name_id" name="first_name" /></li>1030 <li> Last name:<input type="text" name="last_name" id="last_name" /></li>1031 <li> Birthday:<input type="text" name="birthday" id="birthday" /></li>1476 <li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li> 1477 <li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li> 1478 <li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li> 1032 1479 1033 1480 >>> class SignupForm(Form): … … 1056 1503 <textarea name="message"></textarea> 1057 1504 1058 as_textarea() and as_text() are shortcuts for changing the output widget type: 1505 as_textarea(), as_text() and as_hidden() are shortcuts for changing the output 1506 widget type: 1059 1507 >>> f['subject'].as_textarea() 1060 1508 u'<textarea name="subject"></textarea>' 1061 1509 >>> f['message'].as_text() 1062 1510 u'<input type="text" name="message" />' 1511 >>> f['message'].as_hidden() 1512 u'<input type="hidden" name="message" />' 1063 1513 1064 1514 The 'widget' parameter to a Field can also be an instance: … … 1070 1520 <textarea rows="80" cols="20" name="message"></textarea> 1071 1521 1072 Instance-level attrs are *not* carried over to as_textarea() and as_text(): 1522 Instance-level attrs are *not* carried over to as_textarea(), as_text() and 1523 as_hidden(): 1073 1524 >>> f['message'].as_text() 1074 1525 u'<input type="text" name="message" />' … … 1078 1529 >>> f['message'].as_text() 1079 1530 u'<input type="text" name="message" value="I love you." />' 1531 >>> f['message'].as_hidden() 1532 u'<input type="hidden" name="message" value="I love you." />' 1080 1533 1081 1534 For a form with a <select>, use ChoiceField: … … 1096 1549 </select> 1097 1550 1551 Add widget=RadioSelect to use that widget with a ChoiceField. 1552 >>> class FrameworkForm(Form): 1553 ... name = CharField() 1554 ... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect) 1555 >>> f = FrameworkForm() 1556 >>> print f['language'] 1557 <ul> 1558 <li><label><input type="radio" name="language" value="P" /> Python</label></li> 1559 <li><label><input type="radio" name="language" value="J" /> Java</label></li> 1560 </ul> 1561 >>> print f 1562 <tr><td>Name:</td><td><input type="text" name="name" /></td></tr> 1563 <tr><td>Language:</td><td><ul> 1564 <li><label><input type="radio" name="language" value="P" /> Python</label></li> 1565 <li><label><input type="radio" name="language" value="J" /> Java</label></li> 1566 </ul></td></tr> 1567 >>> print f.as_ul() 1568 <li>Name: <input type="text" name="name" /></li> 1569 <li>Language: <ul> 1570 <li><label><input type="radio" name="language" value="P" /> Python</label></li> 1571 <li><label><input type="radio" name="language" value="J" /> Java</label></li> 1572 </ul></li> 1573 1574 Regarding auto_id and <label>, RadioSelect is a special case. Each radio button 1575 gets a distinct ID, formed by appending an underscore plus the button's 1576 zero-based index. 1577 >>> f = FrameworkForm(auto_id='id_%s') 1578 >>> print f['language'] 1579 <ul> 1580 <li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 1581 <li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 1582 </ul> 1583 1584 When RadioSelect is used with auto_id, and the whole form is printed using 1585 either as_table() or as_ul(), the label for the RadioSelect will point to the 1586 ID of the *first* radio button. 1587 >>> print f 1588 <tr><td><label for="id_name">Name:</label></td><td><input type="text" name="name" id="id_name" /></td></tr> 1589 <tr><td><label for="id_language_0">Language:</label></td><td><ul> 1590 <li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 1591 <li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 1592 </ul></td></tr> 1593 >>> print f.as_ul() 1594 <li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li> 1595 <li><label for="id_language_0">Language:</label> <ul> 1596 <li><label><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> 1597 <li><label><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> 1598 </ul></li> 1599 1098 1600 MultipleChoiceField is a special case, as its data is required to be a list: 1099 1601 >>> class SongForm(Form): … … 1122 1624 </select> 1123 1625 1626 MultipleChoiceField can also be used with the CheckboxSelectMultiple widget. 1627 >>> class SongForm(Form): 1628 ... name = CharField() 1629 ... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=CheckboxSelectMultiple) 1630 >>> f = SongForm() 1631 >>> print f['composers'] 1632 <ul> 1633 <li><label><input type="checkbox" name="composers" value="J" /> John Lennon</label></li> 1634 <li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li> 1635 </ul> 1636 >>> f = SongForm({'composers': ['J']}) 1637 >>> print f['composers'] 1638 <ul> 1639 <li><label><input checked="checked" type="checkbox" name="composers" value="J" /> John Lennon</label></li> 1640 <li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li> 1641 </ul> 1642 >>> f = SongForm({'composers': ['J', 'P']}) 1643 >>> print f['composers'] 1644 <ul> 1645 <li><label><input checked="checked" type="checkbox" name="composers" value="J" /> John Lennon</label></li> 1646 <li><label><input checked="checked" type="checkbox" name="composers" value="P" /> Paul McCartney</label></li> 1647 </ul> 1648 1649 When using CheckboxSelectMultiple, the framework expects a list of input and 1650 returns a list of input. 1651 >>> f = SongForm({'name': 'Yesterday'}) 1652 >>> f.errors 1653 {'composers': [u'This field is required.']} 1654 >>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}) 1655 >>> f.errors 1656 {} 1657 >>> f.clean_data 1658 {'composers': [u'J'], 'name': u'Yesterday'} 1659 >>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}) 1660 >>> f.errors 1661 {} 1662 >>> f.clean_data 1663 {'composers': [u'J', u'P'], 'name': u'Yesterday'} 1664 1124 1665 There are a couple of ways to do multiple-field validation. If you want the 1125 1666 validation message to be associated with a particular field, implement the 1126 1667 clean_XXX() method on the Form, where XXX is the field name. As in 1127 Field.clean(), the clean_XXX() method should return the cleaned value: 1668 Field.clean(), the clean_XXX() method should return the cleaned value. In the 1669 clean_XXX() method, you have access to self.clean_data, which is a dictionary 1670 of all the data that has been cleaned *so far*, in order by the fields, 1671 including the current field (e.g., the field XXX if you're in clean_XXX()). 1128 1672 >>> class UserRegistration(Form): 1129 1673 ... username = CharField(max_length=10) … … 1135 1679 ... return self.clean_data['password2'] 1136 1680 >>> f = UserRegistration() 1137 >>> f.errors() 1681 >>> f.errors 1682 {} 1683 >>> f = UserRegistration({}) 1684 >>> f.errors 1138 1685 {'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']} 1139 1686 >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}) 1140 >>> f.errors ()1687 >>> f.errors 1141 1688 {'password2': [u'Please make sure your passwords match.']} 1142 1689 >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}) 1143 >>> f.errors ()1690 >>> f.errors 1144 1691 {} 1145 >>> f.clean ()1692 >>> f.clean_data 1146 1693 {'username': u'adrian', 'password1': u'foo', 'password2': u'foo'} 1147 1694 … … 1149 1696 Form's clean() method. If you do this, any ValidationError raised by that 1150 1697 method will not be associated with a particular field; it will have a 1151 special-case association with the field named '__all__'. Note that 1152 Form.clean() still needs to return a dictionary of all clean data: 1698 special-case association with the field named '__all__'. 1699 Note that in Form.clean(), you have access to self.clean_data, a dictionary of 1700 all the fields/values that have *not* raised a ValidationError. Also note 1701 Form.clean() is required to return a dictionary of all clean data. 1153 1702 >>> class UserRegistration(Form): 1154 1703 ... username = CharField(max_length=10) … … 1160 1709 ... return self.clean_data 1161 1710 >>> f = UserRegistration() 1711 >>> f.errors 1712 {} 1713 >>> f = UserRegistration({}) 1162 1714 >>> print f.as_table() 1715 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1163 1716 <tr><td>Username:</td><td><input type="text" name="username" /></td></tr> 1717 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1164 1718 <tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr> 1719 <tr><td colspan="2"><ul class="errorlist"><li>This field is required.</li></ul></td></tr> 1165 1720 <tr><td>Password2:</td><td><input type="password" name="password2" /></td></tr> 1166 >>> f.errors ()1721 >>> f.errors 1167 1722 {'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']} 1168 1723 >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}) 1169 >>> f.errors ()1724 >>> f.errors 1170 1725 {'__all__': [u'Please make sure your passwords match.']} 1171 1726 >>> print f.as_table() 1727 <tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr> 1172 1728 <tr><td>Username:</td><td><input type="text" name="username" value="adrian" /></td></tr> 1173 1729 <tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr> 1174 1730 <tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr> 1175 >>> print f.as_table_with_errors() 1176 <tr><td colspan="2"><ul><li>Please make sure your passwords match.</li></ul></td></tr> 1177 <tr><td>Username:</td><td><input type="text" name="username" value="adrian" /></td></tr> 1178 <tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr> 1179 <tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr> 1180 >>> print f.as_ul_with_errors() 1181 <li><ul><li>Please make sure your passwords match.</li></ul></li> 1731 >>> print f.as_ul() 1732 <li><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></li> 1182 1733 <li>Username: <input type="text" name="username" value="adrian" /></li> 1183 1734 <li>Password1: <input type="password" name="password1" value="foo" /></li> 1184 1735 <li>Password2: <input type="password" name="password2" value="bar" /></li> 1185 1736 >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}) 1186 >>> f.errors ()1737 >>> f.errors 1187 1738 {} 1188 >>> f.clean ()1739 >>> f.clean_data 1189 1740 {'username': u'adrian', 'password1': u'foo', 'password2': u'foo'} 1190 1741 … … 1203 1754 <tr><td>Last name:</td><td><input type="text" name="last_name" /></td></tr> 1204 1755 <tr><td>Birthday:</td><td><input type="text" name="birthday" /></td></tr> 1756 1757 HiddenInput widgets are displayed differently in the as_table() and as_ul() 1758 output of a Form -- their verbose names are not displayed, and a separate 1759 <tr>/<li> is not displayed. 1760 >>> class Person(Form): 1761 ... first_name = CharField() 1762 ... last_name = CharField() 1763 ... hidden_text = CharField(widget=HiddenInput) 1764 ... birthday = DateField() 1765 >>> p = Person() 1766 >>> print p 1767 <tr><td>First name:</td><td><input type="text" name="first_name" /></td></tr> 1768 <tr><td>Last name:</td><td><input type="text" name="last_name" /></td></tr> 1769 <input type="hidden" name="hidden_text" /> 1770 <tr><td>Birthday:</td><td><input type="text" name="birthday" /></td></tr> 1771 >>> print p.as_ul() 1772 <li>First name: <input type="text" name="first_name" /></li> 1773 <li>Last name: <input type="text" name="last_name" /></li> 1774 <input type="hidden" name="hidden_text" /> 1775 <li>Birthday: <input type="text" name="birthday" /></li> 1776 1777 With auto_id set, a HiddenInput still gets an ID, but it doesn't get a label. 1778 >>> p = Person(auto_id='id_%s') 1779 >>> print p 1780 <tr><td><label for="id_first_name">First name:</label></td><td><input type="text" name="first_name" id="id_first_name" /></td></tr> 1781 <tr><td><label for="id_last_name">Last name:</label></td><td><input type="text" name="last_name" id="id_last_name" /></td></tr> 1782 <input type="hidden" name="hidden_text" id="id_hidden_text" /> 1783 <tr><td><label for="id_birthday">Birthday:</label></td><td><input type="text" name="birthday" id="id_birthday" /></td></tr> 1784 >>> print p.as_ul() 1785 <li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li> 1786 <li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li> 1787 <input type="hidden" name="hidden_text" id="id_hidden_text" /> 1788 <li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li> 1789 1790 If a field with a HiddenInput has errors, the as_table() and as_ul() output 1791 will include the error message(s) with the text "(Hidden field [fieldname]) " 1792 prepended. 1793 >>> p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}) 1794 >>> print p 1795 <tr><td>First name:</td><td><input type="text" name="first_name" value="John" /></td></tr> 1796 <tr><td>Last name:</td><td><input type="text" name="last_name" value="Lennon" /></td></tr> 1797 <tr><td colspan="2"><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></td></tr> 1798 <input type="hidden" name="hidden_text" /> 1799 <tr><td>Birthday:</td><td><input type="text" name="birthday" value="1940-10-9" /></td></tr> 1800 >>> print p.as_ul() 1801 <li>First name: <input type="text" name="first_name" value="John" /></li> 1802 <li>Last name: <input type="text" name="last_name" value="Lennon" /></li> 1803 <li><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></li> 1804 <input type="hidden" name="hidden_text" /> 1805 <li>Birthday: <input type="text" name="birthday" value="1940-10-9" /></li> 1205 1806 1206 1807 A Form's fields are displayed in the same order in which they were defined. … … 1236 1837 <tr><td>Field13:</td><td><input type="text" name="field13" /></td></tr> 1237 1838 <tr><td>Field14:</td><td><input type="text" name="field14" /></td></tr> 1839 1840 # Basic form processing in a view ############################################# 1841 1842 >>> from django.template import Template, Context 1843 >>> class UserRegistration(Form): 1844 ... username = CharField(max_length=10) 1845 ... password1 = CharField(widget=PasswordInput) 1846 ... password2 = CharField(widget=PasswordInput) 1847 ... def clean(self): 1848 ... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: 1849 ... raise ValidationError(u'Please make sure your passwords match.') 1850 ... return self.clean_data 1851 >>> def my_function(method, post_data): 1852 ... if method == 'POST': 1853 ... form = UserRegistration(post_data) 1854 ... else: 1855 ... form = UserRegistration() 1856 ... if form.is_valid(): 1857 ... return 'VALID: %r' % form.clean_data 1858 ... t = Template('<form action="" method="post">\n<table>\n{{ form }}\n</table>\n<input type="submit" />\n</form>') 1859 ... return t.render(Context({'form': form})) 1860 1861 Case 1: GET (an empty form, with no errors). 1862 >>> print my_function('GET', {}) 1863 <form action="" method="post"> 1864 <table> 1865 <tr><td>Username:</td><td><input type="text" name="username" /></td></tr> 1866 <tr><td>Password1:</td><td><input type="password" name="password1" /></td></tr> 1867 <tr><td>Password2:</td><td><input type="password" name="password2" /></td></tr> 1868 </table> 1869 <input type="submit" /> 1870 </form> 1871 1872 Case 2: POST with erroneous data (a redisplayed form, with errors). 1873 >>> print my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'}) 1874 <form action="" method="post"> 1875 <table> 1876 <tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr> 1877 <tr><td colspan="2"><ul class="errorlist"><li>Ensure this value has at most 10 characters.</li></ul></td></tr> 1878 <tr><td>Username:</td><td><input type="text" name="username" value="this-is-a-long-username" /></td></tr> 1879 <tr><td>Password1:</td><td><input type="password" name="password1" value="foo" /></td></tr> 1880 <tr><td>Password2:</td><td><input type="password" name="password2" value="bar" /></td></tr> 1881 </table> 1882 <input type="submit" /> 1883 </form> 1884 1885 Case 3: POST with valid data (the success message). 1886 >>> print my_function('POST', {'username': 'adrian', 'password1': 'secret', 'password2': 'secret'}) 1887 VALID: {'username': u'adrian', 'password1': u'secret', 'password2': u'secret'} 1888 1889 # Some ideas for using templates with forms ################################### 1890 1891 >>> class UserRegistration(Form): 1892 ... username = CharField(max_length=10) 1893 ... password1 = CharField(widget=PasswordInput) 1894 ... password2 = CharField(widget=PasswordInput) 1895 ... def clean(self): 1896 ... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: 1897 ... raise ValidationError(u'Please make sure your passwords match.') 1898 ... return self.clean_data 1899 1900 You have full flexibility in displaying form fields in a template. Just pass a 1901 Form instance to the template, and use "dot" access to refer to individual 1902 fields. Note, however, that this flexibility comes with the responsibility of 1903 displaying all the errors, including any that might not be associated with a 1904 particular field. 1905 >>> t = Template('''<form action=""> 1906 ... {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p> 1907 ... {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p> 1908 ... {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p> 1909 ... <input type="submit" /> 1910 ... </form>''') 1911 >>> print t.render(Context({'form': UserRegistration()})) 1912 <form action=""> 1913 <p><label>Your username: <input type="text" name="username" /></label></p> 1914 <p><label>Password: <input type="password" name="password1" /></label></p> 1915 <p><label>Password (again): <input type="password" name="password2" /></label></p> 1916 <input type="submit" /> 1917 </form> 1918 >>> print t.render(Context({'form': UserRegistration({'username': 'django'})})) 1919 <form action=""> 1920 <p><label>Your username: <input type="text" name="username" value="django" /></label></p> 1921 <ul class="errorlist"><li>This field is required.</li></ul><p><label>Password: <input type="password" name="password1" /></label></p> 1922 <ul class="errorlist"><li>This field is required.</li></ul><p><label>Password (again): <input type="password" name="password2" /></label></p> 1923 <input type="submit" /> 1924 </form> 1925 1926 Use form.[field].verbose_name to output a field's "verbose name" -- its field 1927 name with underscores converted to spaces, and the initial letter capitalized. 1928 >>> t = Template('''<form action=""> 1929 ... <p><label>{{ form.username.verbose_name }}: {{ form.username }}</label></p> 1930 ... <p><label>{{ form.password1.verbose_name }}: {{ form.password1 }}</label></p> 1931 ... <p><label>{{ form.password2.verbose_name }}: {{ form.password2 }}</label></p> 1932 ... <input type="submit" /> 1933 ... </form>''') 1934 >>> print t.render(Context({'form': UserRegistration()})) 1935 <form action=""> 1936 <p><label>Username: <input type="text" name="username" /></label></p> 1937 <p><label>Password1: <input type="password" name="password1" /></label></p> 1938 <p><label>Password2: <input type="password" name="password2" /></label></p> 1939 <input type="submit" /> 1940 </form> 1941 1942 User form.[field].label_tag to output a field's verbose_name with a <label> 1943 tag wrapped around it, but *only* if the given field has an "id" attribute. 1944 Recall from above that passing the "auto_id" argument to a Form gives each 1945 field an "id" attribute. 1946 >>> t = Template('''<form action=""> 1947 ... <p>{{ form.username.label_tag }}: {{ form.username }}</p> 1948 ... <p>{{ form.password1.label_tag }}: {{ form.password1 }}</p> 1949 ... <p>{{ form.password2.label_tag }}: {{ form.password2 }}</p> 1950 ... <input type="submit" /> 1951 ... </form>''') 1952 >>> print t.render(Context({'form': UserRegistration()})) 1953 <form action=""> 1954 <p>Username: <input type="text" name="username" /></p> 1955 <p>Password1: <input type="password" name="password1" /></p> 1956 <p>Password2: <input type="password" name="password2" /></p> 1957 <input type="submit" /> 1958 </form> 1959 >>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')})) 1960 <form action=""> 1961 <p><label for="id_username">Username</label>: <input type="text" name="username" id="id_username" /></p> 1962 <p><label for="id_password1">Password1</label>: <input type="password" name="password1" id="id_password1" /></p> 1963 <p><label for="id_password2">Password2</label>: <input type="password" name="password2" id="id_password2" /></p> 1964 <input type="submit" /> 1965 </form> 1966 1967 To display the errors that aren't associated with a particular field -- e.g., 1968 the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the 1969 template. If used on its own, it is displayed as a <ul> (or an empty string, if 1970 the list of errors is empty). You can also use it in {% if %} statements. 1971 >>> t = Template('''<form action=""> 1972 ... {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p> 1973 ... {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p> 1974 ... {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p> 1975 ... <input type="submit" /> 1976 ... </form>''') 1977 >>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})})) 1978 <form action=""> 1979 <p><label>Your username: <input type="text" name="username" value="django" /></label></p> 1980 <p><label>Password: <input type="password" name="password1" value="foo" /></label></p> 1981 <p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p> 1982 <input type="submit" /> 1983 </form> 1984 >>> t = Template('''<form action=""> 1985 ... {{ form.non_field_errors }} 1986 ... {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p> 1987 ... {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p> 1988 ... {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p> 1989 ... <input type="submit" /> 1990 ... </form>''') 1991 >>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})})) 1992 <form action=""> 1993 <ul class="errorlist"><li>Please make sure your passwords match.</li></ul> 1994 <p><label>Your username: <input type="text" name="username" value="django" /></label></p> 1995 <p><label>Password: <input type="password" name="password1" value="foo" /></label></p> 1996 <p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p> 1997 <input type="submit" /> 1998 </form> 1238 1999 """ 1239 2000
