Changeset 5244
- Timestamp:
- 05/14/07 22:37:41 (2 years ago)
- Files:
-
- django/branches/newforms-admin (modified) (1 prop)
- django/branches/newforms-admin/AUTHORS (modified) (2 diffs)
- django/branches/newforms-admin/django/conf/global_settings.py (modified) (1 diff)
- django/branches/newforms-admin/django/conf/locale/bg (copied) (copied from django/trunk/django/conf/locale/bg)
- django/branches/newforms-admin/django/conf/locale/bg/LC_MESSAGES (copied) (copied from django/trunk/django/conf/locale/bg/LC_MESSAGES)
- django/branches/newforms-admin/django/conf/locale/bg/LC_MESSAGES/djangojs.mo (copied) (copied from django/trunk/django/conf/locale/bg/LC_MESSAGES/djangojs.mo)
- django/branches/newforms-admin/django/conf/locale/bg/LC_MESSAGES/djangojs.po (copied) (copied from django/trunk/django/conf/locale/bg/LC_MESSAGES/djangojs.po)
- django/branches/newforms-admin/django/conf/locale/bg/LC_MESSAGES/django.mo (copied) (copied from django/trunk/django/conf/locale/bg/LC_MESSAGES/django.mo)
- django/branches/newforms-admin/django/conf/locale/bg/LC_MESSAGES/django.po (copied) (copied from django/trunk/django/conf/locale/bg/LC_MESSAGES/django.po)
- django/branches/newforms-admin/django/contrib/formtools/preview.py (modified) (3 diffs)
- django/branches/newforms-admin/django/contrib/localflavor/is_/forms.py (modified) (1 diff)
- django/branches/newforms-admin/django/core/management.py (modified) (2 diffs)
- django/branches/newforms-admin/django/core/serializers/python.py (modified) (2 diffs)
- django/branches/newforms-admin/django/core/serializers/xml_serializer.py (modified) (2 diffs)
- django/branches/newforms-admin/django/db/backends/postgresql/base.py (modified) (2 diffs)
- django/branches/newforms-admin/django/db/backends/postgresql_psycopg2/base.py (modified) (2 diffs)
- django/branches/newforms-admin/django/newforms/formsets.py (modified) (5 diffs)
- django/branches/newforms-admin/django/newforms/forms.py (modified) (5 diffs)
- django/branches/newforms-admin/django/newforms/models.py (modified) (5 diffs)
- django/branches/newforms-admin/django/test/testcases.py (modified) (7 diffs)
- django/branches/newforms-admin/docs/databrowse.txt (modified) (1 diff)
- django/branches/newforms-admin/docs/i18n.txt (modified) (1 diff)
- django/branches/newforms-admin/docs/newforms.txt (modified) (19 diffs)
- django/branches/newforms-admin/docs/testing.txt (modified) (5 diffs)
- django/branches/newforms-admin/tests/modeltests/model_forms/models.py (modified) (8 diffs)
- django/branches/newforms-admin/tests/regressiontests/forms/formsets.py (modified) (11 diffs)
- django/branches/newforms-admin/tests/regressiontests/forms/regressions.py (modified) (1 diff)
- django/branches/newforms-admin/tests/regressiontests/forms/tests.py (modified) (24 diffs)
- django/branches/newforms-admin/tests/regressiontests/serializers_regress/models.py (modified) (2 diffs)
- django/branches/newforms-admin/tests/regressiontests/serializers_regress/tests.py (modified) (2 diffs)
- django/branches/newforms-admin/tests/regressiontests/test_client_regress/models.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/newforms-admin
- Property svnmerge-integrated changed from /django/trunk:1-4345,4350-4357,4359-4365,4371-4372,4374-4377,4380-4386,4388,4390-4391,4400-4402,4404-4408,4410,4412-4419,4426-4427,4430-4432,4434,4441,4443-4444,4446-4447,4450,4452-4453,4455-4458,4476,4503,4546,4564-4569,4580-4586,4617,4630,4641-5194 to /django/trunk:1-4345,4350-4357,4359-4365,4371-4372,4374-4377,4380-4386,4388,4390-4391,4400-4402,4404-4408,4410,4412-4419,4426-4427,4430-4432,4434,4441,4443-4444,4446-4447,4450,4452-4453,4455-4458,4476,4503,4546,4564-4569,4580-4586,4617,4630,4641-5243
django/branches/newforms-admin/AUTHORS
r5195 r5244 79 79 Jure Cuhalev <gandalf@owca.info> 80 80 dackze+django@gmail.com 81 David Danier <goliath.mailinglist@gmx.de> 81 82 Dirk Datzert <dummy@habmalnefrage.de> 82 83 Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/> … … 86 87 deric@monowerks.com 87 88 Max Derkachev <mderk@yandex.ru> 89 Jordan Dimov <s3x3y1@gmail.com> 88 90 dne@mayonnaise.net 89 91 Maximillian Dornseif <md@hudora.de> django/branches/newforms-admin/django/conf/global_settings.py
r5195 r5244 39 39 ('ar', gettext_noop('Arabic')), 40 40 ('bn', gettext_noop('Bengali')), 41 ('bg', gettext_noop('Bulgarian')), 41 42 ('ca', gettext_noop('Catalan')), 42 43 ('cs', gettext_noop('Czech')), django/branches/newforms-admin/django/contrib/formtools/preview.py
r4265 r5244 25 25 Subclass FormPreview and define a done() method: 26 26 27 def done(self, request, clean _data):27 def done(self, request, cleaned_data): 28 28 # ... 29 29 … … 114 114 if self.security_hash(request, f) != request.POST.get(self.unused_name('hash')): 115 115 return self.failed_hash(request) # Security hash failed. 116 return self.done(request, f.clean _data)116 return self.done(request, f.cleaned_data) 117 117 else: 118 118 return render_to_response(self.form_template, … … 161 161 # METHODS SUBCLASSES MUST OVERRIDE ######################################## 162 162 163 def done(self, request, clean_data): 164 "Does something with the clean_data and returns an HttpResponseRedirect." 163 def done(self, request, cleaned_data): 164 """ 165 Does something with the cleaned_data and returns an 166 HttpResponseRedirect. 167 """ 165 168 raise NotImplementedError('You must define a done() method on your %s subclass.' % self.__class__.__name__) django/branches/newforms-admin/django/contrib/localflavor/is_/forms.py
r5195 r5244 42 42 """ 43 43 check = [3, 2, 7, 6, 5, 4, 3, 2, 1, 0] 44 return sum( int(value[i]) * check[i] for i in range(10)) % 11 == 044 return sum([int(value[i]) * check[i] for i in range(10)]) % 11 == 0 45 45 46 46 def _format(self, value): django/branches/newforms-admin/django/core/management.py
r5195 r5244 1408 1408 print "No %s fixture '%s' in %s." % \ 1409 1409 (format, fixture_name, humanize(fixture_dir)) 1410 1411 if count[0] > 0: 1412 sequence_sql = backend.get_sql_sequence_reset(style, models) 1413 if sequence_sql: 1414 if verbosity > 1: 1415 print "Resetting sequences" 1416 for line in sequence_sql: 1417 cursor.execute(line) 1418 1419 transaction.commit() 1420 transaction.leave_transaction_management() 1421 1410 1422 if count[0] == 0: 1411 1423 if verbosity > 0: … … 1414 1426 if verbosity > 0: 1415 1427 print "Installed %d object(s) from %d fixture(s)" % tuple(count) 1416 sequence_sql = backend.get_sql_sequence_reset(style, models)1417 if sequence_sql:1418 if verbosity > 1:1419 print "Resetting sequences"1420 for line in sequence_sql:1421 cursor.execute(line)1422 transaction.commit()1423 transaction.leave_transaction_management()1424 1428 1425 1429 load_data.help_doc = 'Installs the named fixture(s) in the database' django/branches/newforms-admin/django/core/serializers/python.py
r4750 r5244 38 38 related = getattr(obj, field.name) 39 39 if related is not None: 40 related = related._get_pk_val()40 related = getattr(related, field.rel.field_name) 41 41 self._current[field.name] = related 42 42 … … 81 81 # Handle FK fields 82 82 elif field.rel and isinstance(field.rel, models.ManyToOneRel): 83 data[field.attname] = field.rel.to._meta.pk.to_python(field_value) 83 if field_value: 84 data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value) 85 else: 86 data[field.attname] = None 84 87 85 88 # Handle all other fields django/branches/newforms-admin/django/core/serializers/xml_serializer.py
r4750 r5244 83 83 related = getattr(obj, field.name) 84 84 if related is not None: 85 self.xml.characters(str( related._get_pk_val()))85 self.xml.characters(str(getattr(related, field.rel.field_name))) 86 86 else: 87 87 self.xml.addQuickElement("None") … … 182 182 return None 183 183 else: 184 return field.rel.to._meta. pk.to_python(184 return field.rel.to._meta.get_field(field.rel.field_name).to_python( 185 185 getInnerText(node).strip().encode(self.encoding)) 186 186 django/branches/newforms-admin/django/db/backends/postgresql/base.py
r5195 r5244 224 224 output.append("%s setval('%s', (%s max(%s) %s %s));" % \ 225 225 (style.SQL_KEYWORD('SELECT'), 226 style.SQL_FIELD( '%s_%s_seq' % (model._meta.db_table, f.column)),226 style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), 227 227 style.SQL_KEYWORD('SELECT'), 228 228 style.SQL_FIELD(quote_name(f.column)), … … 233 233 output.append("%s setval('%s', (%s max(%s) %s %s));" % \ 234 234 (style.SQL_KEYWORD('SELECT'), 235 style.SQL_FIELD( '%s_id_seq' % f.m2m_db_table()),235 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), 236 236 style.SQL_KEYWORD('SELECT'), 237 237 style.SQL_FIELD(quote_name('id')), django/branches/newforms-admin/django/db/backends/postgresql_psycopg2/base.py
r5195 r5244 181 181 output.append("%s setval('%s', (%s max(%s) %s %s));" % \ 182 182 (style.SQL_KEYWORD('SELECT'), 183 style.SQL_FIELD( '%s_%s_seq' % (model._meta.db_table, f.column)),183 style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), 184 184 style.SQL_KEYWORD('SELECT'), 185 185 style.SQL_FIELD(quote_name(f.column)), … … 190 190 output.append("%s setval('%s', (%s max(%s) %s %s));" % \ 191 191 (style.SQL_KEYWORD('SELECT'), 192 style.SQL_FIELD( '%s_id_seq' % f.m2m_db_table()),192 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), 193 193 style.SQL_KEYWORD('SELECT'), 194 194 style.SQL_FIELD(quote_name('id')), django/branches/newforms-admin/django/newforms/formsets.py
r4953 r5244 34 34 self.management_form = ManagementForm(data, auto_id=self.auto_id, prefix=self.prefix) 35 35 if self.management_form.is_valid(): 36 self.total_forms = self.management_form.clean _data[FORM_COUNT_FIELD_NAME]36 self.total_forms = self.management_form.cleaned_data[FORM_COUNT_FIELD_NAME] 37 37 self.required_forms = self.total_forms - self.num_extra 38 38 else: … … 68 68 def full_clean(self): 69 69 """ 70 Cleans all of self.data and populates self.__errors and self.clean _data.70 Cleans all of self.data and populates self.__errors and self.cleaned_data. 71 71 """ 72 72 is_valid = True … … 76 76 self.__errors = errors 77 77 return 78 clean _data = []78 cleaned_data = [] 79 79 deleted_data = [] 80 80 … … 104 104 else: 105 105 # if the formset is still vaild overall and this form instance 106 # is valid, keep appending to clean _data106 # is valid, keep appending to cleaned_data 107 107 if is_valid and form.is_valid(): 108 if self.deletable and form.clean _data[DELETION_FIELD_NAME]:109 deleted_data.append(form.clean _data)108 if self.deletable and form.cleaned_data[DELETION_FIELD_NAME]: 109 deleted_data.append(form.cleaned_data) 110 110 else: 111 clean _data.append(form.clean_data)111 cleaned_data.append(form.cleaned_data) 112 112 else: 113 113 is_valid = False … … 118 118 deleted_data.reverse() 119 119 if self.orderable: 120 clean _data.sort(lambda x,y: x[ORDERING_FIELD_NAME] - y[ORDERING_FIELD_NAME])120 cleaned_data.sort(lambda x,y: x[ORDERING_FIELD_NAME] - y[ORDERING_FIELD_NAME]) 121 121 else: 122 clean _data.reverse()122 cleaned_data.reverse() 123 123 errors.reverse() 124 124 self._form_list.reverse() 125 125 126 126 if is_valid: 127 self.clean _data = clean_data127 self.cleaned_data = cleaned_data 128 128 self.deleted_data = deleted_data 129 129 self.errors = errors django/branches/newforms-admin/django/newforms/forms.py
r5195 r5244 188 188 def full_clean(self): 189 189 """ 190 Cleans all of self.data and populates self.__errors and self.clean _data.190 Cleans all of self.data and populates self.__errors and self.cleaned_data. 191 191 """ 192 192 errors = ErrorDict() … … 194 194 self.__errors = errors 195 195 return 196 self.clean _data = {}196 self.cleaned_data = {} 197 197 for name, field in self.fields.items(): 198 198 # value_from_datadict() gets the data from the dictionary. … … 202 202 try: 203 203 value = field.clean(value) 204 self.clean _data[name] = value204 self.cleaned_data[name] = value 205 205 if hasattr(self, 'clean_%s' % name): 206 206 value = getattr(self, 'clean_%s' % name)() 207 self.clean _data[name] = value207 self.cleaned_data[name] = value 208 208 except ValidationError, e: 209 209 errors[name] = e.messages 210 210 try: 211 self.clean _data = self.clean()211 self.cleaned_data = self.clean() 212 212 except ValidationError, e: 213 213 errors[NON_FIELD_ERRORS] = e.messages 214 214 if errors: 215 delattr(self, 'clean _data')215 delattr(self, 'cleaned_data') 216 216 self.__errors = errors 217 217 … … 223 223 association with the field named '__all__'. 224 224 """ 225 return self.clean _data225 return self.cleaned_data 226 226 227 227 class Form(BaseForm): … … 274 274 if not self.form.is_bound: 275 275 data = self.form.initial.get(self.name, self.field.initial) 276 if callable(data): 277 data = data() 276 278 else: 277 279 data = self.data django/branches/newforms-admin/django/newforms/models.py
r4940 r5244 13 13 'ModelChoiceField', 'ModelMultipleChoiceField') 14 14 15 def model_save(self, commit=True):15 def save_instance(form, instance, fields=None, fail_message='saved', commit=True): 16 16 """ 17 Creates and returns model instance according to self.clean_data. 18 19 This method is created for any form_for_model Form. 20 """ 21 if self.errors: 22 raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name) 23 return save_instance(self, self._model(), commit) 24 25 def save_instance(form, instance, commit=True): 26 """ 27 Saves bound Form ``form``'s clean_data into model instance ``instance``. 17 Saves bound Form ``form``'s cleaned_data into model instance ``instance``. 28 18 29 19 Assumes ``form`` has a field for every non-AutoField database field in … … 34 24 opts = instance.__class__._meta 35 25 if form.errors: 36 raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name)37 clean _data = form.clean_data26 raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message)) 27 cleaned_data = form.cleaned_data 38 28 for f in opts.fields: 39 if not f.editable or isinstance(f, models.AutoField) or not f.name in clean _data:29 if not f.editable or isinstance(f, models.AutoField) or not f.name in cleaned_data: 40 30 continue 41 setattr(instance, f.name, clean_data[f.name]) 31 if fields and f.name not in fields: 32 continue 33 setattr(instance, f.name, cleaned_data[f.name]) 42 34 if commit: 43 35 instance.save() 44 36 for f in opts.many_to_many: 45 if f.name in clean_data: 46 setattr(instance, f.attname, clean_data[f.name]) 37 if fields and f.name not in fields: 38 continue 39 if f.name in cleaned_data: 40 setattr(instance, f.attname, cleaned_data[f.name]) 47 41 # GOTCHA: If many-to-many data is given and commit=False, the many-to-many 48 42 # data will be lost. This happens because a many-to-many options cannot be … … 51 45 return instance 52 46 53 def make_ instance_save(instance):54 "Returns the save() method for a form_for_instanceForm."47 def make_model_save(model, fields, fail_message): 48 "Returns the save() method for a Form." 55 49 def save(self, commit=True): 56 return save_instance(self, instance, commit) 50 return save_instance(self, model(), fields, fail_message, commit) 51 return save 52 53 def make_instance_save(instance, fields, fail_message): 54 "Returns the save() method for a Form." 55 def save(self, commit=True): 56 return save_instance(self, instance, fields, fail_message, commit) 57 57 return save 58 58 59 def form_for_model(model, form=BaseForm, f ormfield_callback=lambda f: f.formfield()):59 def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda f: f.formfield()): 60 60 """ 61 61 Returns a Form class for the given Django model class. … … 72 72 if not f.editable: 73 73 continue 74 if fields and not f.name in fields: 75 continue 74 76 formfield = formfield_callback(f) 75 77 if formfield: 76 78 field_list.append((f.name, formfield)) 77 fields = SortedDictFromList(field_list) 78 return type(opts.object_name + 'Form', (form,), {'base_fields': fields, '_model': model, 'save': model_save}) 79 base_fields = SortedDictFromList(field_list) 80 return type(opts.object_name + 'Form', (form,), 81 {'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')}) 79 82 80 def form_for_instance(instance, form=BaseForm, f ormfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):83 def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)): 81 84 """ 82 85 Returns a Form class for the given Django model instance. … … 95 98 if not f.editable: 96 99 continue 100 if fields and not f.name in fields: 101 continue 97 102 current_value = f.value_from_object(instance) 98 103 formfield = formfield_callback(f, initial=current_value) 99 104 if formfield: 100 105 field_list.append((f.name, formfield)) 101 fields = SortedDictFromList(field_list)106 base_fields = SortedDictFromList(field_list) 102 107 return type(opts.object_name + 'InstanceForm', (form,), 103 {'base_fields': fields, '_model': model, 'save': make_instance_save(instance)})108 {'base_fields': base_fields, '_model': model, 'save': make_instance_save(instance, fields, 'changed')}) 104 109 105 110 def form_for_fields(field_list): django/branches/newforms-admin/django/test/testcases.py
r5195 r5244 46 46 management.load_data(self.fixtures, verbosity=0) 47 47 mail.outbox = [] 48 49 def run(self, result=None):50 """ Wrapper around default run method to perform common Django test set up.51 This means that user-defined Test Cases aren't required to include a call52 to super().setUp().53 48 49 def __call__(self, result=None): 50 """ 51 Wrapper around default __call__ method to perform common Django test 52 set up. This means that user-defined Test Cases aren't required to 53 include a call to super().setUp(). 54 54 """ 55 55 self.client = Client() 56 56 self._pre_setup() 57 super(TestCase, self). run(result)57 super(TestCase, self).__call__(result) 58 58 59 59 def assertRedirects(self, response, expected_path, status_code=302, target_status_code=200): … … 63 63 """ 64 64 self.assertEqual(response.status_code, status_code, 65 "Response didn't redirect : Reponse code was %d (expected %d)" %65 "Response didn't redirect as expected: Reponse code was %d (expected %d)" % 66 66 (response.status_code, status_code)) 67 67 scheme, netloc, path, params, query, fragment = urlparse(response['Location']) … … 71 71 self.assertEqual(redirect_response.status_code, target_status_code, 72 72 "Couldn't retrieve redirection page '%s': response code was %d (expected %d)" % 73 (path, re sponse.status_code,status_code))73 (path, redirect_response.status_code, target_status_code)) 74 74 75 75 def assertContains(self, response, text, count=1, status_code=200): … … 109 109 if field: 110 110 if field in context[form].errors: 111 self. assertTrue(err in context[form].errors[field],111 self.failUnless(err in context[form].errors[field], 112 112 "The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" % 113 113 (field, form, i, err, list(context[form].errors[field]))) … … 118 118 self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field)) 119 119 else: 120 self. assertTrue(err in context[form].non_field_errors(),120 self.failUnless(err in context[form].non_field_errors(), 121 121 "The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" % 122 122 (form, i, err, list(context[form].non_field_errors()))) … … 128 128 if isinstance(response.template, list): 129 129 template_names = [t.name for t in response.template] 130 self. assertTrue(template_name in template_names,130 self.failUnless(template_name in template_names, 131 131 "Template '%s' was not one of the templates used to render the response. Templates used: %s" % 132 132 (template_name, template_names)) … … 141 141 "Assert that the template with the provided name was NOT used in rendering the response" 142 142 if isinstance(response.template, list): 143 self. assertFalse(template_name in [t.name for t in response.template],143 self.failIf(template_name in [t.name for t in response.template], 144 144 "Template '%s' was used unexpectedly in rendering the response" % template_name) 145 145 elif response.template: django/branches/newforms-admin/docs/databrowse.txt
r5195 r5244 45 45 some point. A good place for it is in your URLconf file (``urls.py``). 46 46 47 3. Add the following line to your URLconf:: 47 3. Change your URLconf to import the ``databrowse`` module:: 48 49 from django.contrib import databrowse 50 51 ...and add the following line to your URLconf:: 48 52 49 53 (r'^databrowse/(.*)', databrowse.site.root), django/branches/newforms-admin/docs/i18n.txt
r5195 r5244 237 237 ``{% endblocktrans %}``. Example:: 238 238 239 {% blocktrans count list| countas counter %}239 {% blocktrans count list|length as counter %} 240 240 There is only one {{ name }} object. 241 241 {% plural %} django/branches/newforms-admin/docs/newforms.txt
r4824 r5244 10 10 ============== 11 11 12 ``django.newforms`` currently is only available in Django beginning 13 with the 0.96 release. the Django development version -- i.e., it's 14 not available in the Django 0.95 release. For the next Django release, 15 our plan is to do the following: 16 17 * As of revision [4208], we've copied the current ``django.forms`` to 18 ``django.oldforms``. This allows you to upgrade your code *now* rather 19 than waiting for the backwards-incompatible change and rushing to fix 20 your code after the fact. Just change your import statements like this:: 12 ``django.newforms`` is new in Django's 0.96 release, but, as it won't be new 13 forever, we plan to rename it to ``django.forms`` in the future. The current 14 ``django.forms`` package will be available as ``django.oldforms`` until Django 15 1.0, when we plan to remove it for good. 16 17 That has direct repercussions on the forward compatibility of your code. Please 18 read the following migration plan and code accordingly: 19 20 * The old forms framework (the current ``django.forms``) has been copied to 21 ``django.oldforms``. Thus, you can start upgrading your code *now*, 22 rather than waiting for the future backwards-incompatible change, by 23 changing your import statements like this:: 21 24 22 25 from django import forms # old 23 26 from django import oldforms as forms # new 24 27 25 * At an undecided future date, we will move the current ``django.newforms``26 to ``django.forms``. This will be a backwards-incompatible change, and27 anybody who is still using the old version of ``django.forms`` at that28 time will need to change their import statements, as described in the29 previous bullet.28 * In the next Django release (0.97), we will move the current 29 ``django.newforms`` to ``django.forms``. This will be a 30 backwards-incompatible change, and anybody who is still using the old 31 version of ``django.forms`` at that time will need to change their import 32 statements, as described in the previous bullet. 30 33 31 34 * We will remove ``django.oldforms`` in the release *after* the next Django 32 release -- the release that comes after the release in which we're 33 creating the new ``django.forms``. 35 release -- either 0.98 or 1.0, whichever comes first. 34 36 35 37 With this in mind, we recommend you use the following import statement when … … 185 187 False 186 188 187 Access the `` Form`` attribute ``errors``to get a dictionary of error messages::189 Access the ``errors`` attribute to get a dictionary of error messages:: 188 190 189 191 >>> f.errors … … 197 199 form's data will be validated the first time either you call ``is_valid()`` or 198 200 access ``errors``. 201 202 The validation routines will only get called once, regardless of how many times 203 you access ``errors`` or call ``is_valid()``. This means that if validation has 204 side effects, those side effects will only be triggered once. 199 205 200 206 Behavior of unbound forms … … 225 231 226 232 Once you've created a ``Form`` instance with a set of data and validated it, 227 you can access the clean data via the ``clean _data`` attribute of the ``Form``233 you can access the clean data via the ``cleaned_data`` attribute of the ``Form`` 228 234 object:: 229 235 … … 235 241 >>> f.is_valid() 236 242 True 237 >>> f.clean _data243 >>> f.cleaned_data 238 244 {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} 239 245 … … 243 249 244 250 If your data does *not* validate, your ``Form`` instance will not have a 245 ``clean _data`` attribute::251 ``cleaned_data`` attribute:: 246 252 247 253 >>> data = {'subject': '', … … 252 258 >>> f.is_valid() 253 259 False 254 >>> f.clean _data260 >>> f.cleaned_data 255 261 Traceback (most recent call last): 256 262 ... 257 AttributeError: 'ContactForm' object has no attribute 'clean _data'258 259 ``clean _data`` will always *only* contain a key for fields defined in the263 AttributeError: 'ContactForm' object has no attribute 'cleaned_data' 264 265 ``cleaned_data`` will always *only* contain a key for fields defined in the 260 266 ``Form``, even if you pass extra data when you define the ``Form``. In this 261 267 example, we pass a bunch of extra fields to the ``ContactForm`` constructor, 262 but ``clean _data`` contains only the form's fields::268 but ``cleaned_data`` contains only the form's fields:: 263 269 264 270 >>> data = {'subject': 'hello', … … 272 278 >>> f.is_valid() 273 279 True 274 >>> f.clean _data # Doesn't contain extra_field_1, etc.280 >>> f.cleaned_data # Doesn't contain extra_field_1, etc. 275 281 {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} 282 283 ``cleaned_data`` will include a key and value for *all* fields defined in the 284 ``Form``, even if the data didn't include a value for fields that are not 285 required. In this example, the data dictionary doesn't include a value for the 286 ``nick_name`` field, but ``cleaned_data`` includes it, with an empty value:: 287 288 >>> class OptionalPersonForm(Form): 289 ... first_name = CharField() 290 ... last_name = CharField() 291 ... nick_name = CharField(required=False) 292 >>> data = {'first_name': u'John', 'last_name': u'Lennon'} 293 >>> f = OptionalPersonForm(data) 294 >>> f.is_valid() 295 True 296 >>> f.cleaned_data 297 {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} 298 299 In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an 300 empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat 301 empty values as an empty string. Each field type knows what its "blank" value 302 is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. 276 303 277 304 Behavior of unbound forms … … 282 309 283 310 >>> f = ContactForm() 284 >>> f.clean _data311 >>> f.cleaned_data 285 312 Traceback (most recent call last): 286 313 ... 287 AttributeError: 'ContactForm' object has no attribute 'clean _data'314 AttributeError: 'ContactForm' object has no attribute 'cleaned_data' 288 315 289 316 Outputting forms as HTML … … 455 482 then the form output will include ``<label>`` tags, and will generate ``id`` 456 483 attributes based on the format string. For example, for a format string 457 ``'field_%s'``, a field named ``subject`` will get the ``id`` 484 ``'field_%s'``, a field named ``subject`` will get the ``id`` value 458 485 ``'field_subject'``. Continuing our example:: 459 486 … … 494 521 If you render a bound ``Form`` object, the act of rendering will automatically 495 522 run the form's validation if it hasn't already happened, and the HTML output 496 will include the validation errors as a ``<ul>`` near the field. The particular 497 positioning of the error messages depends on the output method you're using:: 523 will include the validation errors as a ``<ul class="errorlist">`` near the 524 field. The particular positioning of the error messages depends on the output 525 method you're using:: 498 526 499 527 >>> data = {'subject': '', … … 557 585 558 586 For a field's list of errors, access the field's ``errors`` attribute. This 559 is a list-like object that is displayed as an HTML ``<ul>`` when printed:: 587 is a list-like object that is displayed as an HTML ``<ul class="errorlist">`` 588 when printed:: 560 589 561 590 >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} … … 647 676 Each ``Field`` class constructor takes at least these arguments. Some 648 677 ``Field`` classes take additional, field-specific arguments, but the following 649 should *always* be a vailable:678 should *always* be accepted: 650 679 651 680 ``required`` … … 705 734 field. This is used when the ``Field`` is displayed in a ``Form``. 706 735 707 As explained in _`Outputting forms as HTML`above, the default label for a736 As explained in "Outputting forms as HTML" above, the default label for a 708 737 ``Field`` is generated from the field name by converting all underscores to 709 738 spaces and upper-casing the first letter. Specify ``label`` if that default … … 780 809 781 810 The ``widget`` argument lets you specify a ``Widget`` class to use when 782 rendering this ``Field``. See _`Widgets`below for more information.811 rendering this ``Field``. See "Widgets" below for more information. 783 812 784 813 ``help_text`` … … 787 816 The ``help_text`` argument lets you specify descriptive text for this 788 817 ``Field``. If you provide ``help_text``, it will be displayed next to the 789 ``Field`` when the ``Field`` is rendered in a ``Form``. 818 ``Field`` when the ``Field`` is rendered by one of the convenience ``Form`` 819 methods (e.g., ``as_ul()``). 790 820 791 821 Here's a full example ``Form`` that implements ``help_text`` for two of its … … 861 891 <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> 862 892 893 Built-in ``Field`` classes 894 -------------------------- 895 896 Naturally, the ``newforms`` library comes with a set of ``Field`` classes that 897 represent common validation needs. This section documents each built-in field. 898 899 For each field, we describe the default widget used if you don't specify 900 ``widget``. We also specify the value returned when you provide an empty value 901 (see the section on ``required`` above to understand what that means). 902 903 ``BooleanField`` 904 ~~~~~~~~~~~~~~~~ 905 906 * Default widget: ``CheckboxInput`` 907 * Empty value: ``None`` 908 * Normalizes to: A Python ``True`` or ``False`` value. 909 * Validates nothing (i.e., it never raises a ``ValidationError``). 910 911 ``CharField`` 912 ~~~~~~~~~~~~~ 913 914 * Default widget: ``TextInput`` 915 * Empty value: ``''`` (an empty string) 916 * Normalizes to: A Unicode object. 917 * Validates nothing, unless ``max_length`` or ``min_length`` is provided. 918 919 Has two optional arguments for validation, ``max_length`` and ``min_length``. 920 If provided, these arguments ensure that the string is at most or at least the 921 given length. 922 923 ``ChoiceField`` 924 ~~~~~~~~~~~~~~~ 925 926 * Default widget: ``Select`` 927 * Empty value: ``''`` (an empty string) 928 * Normalizes to: A Unicode object. 929 * Validates that the given value exists in the list of choices. 930 931 Takes one extra argument, ``choices``, which is an iterable (e.g., a list or 932 tuple) of 2-tuples to use as choices for this field. 933 934 ``DateField`` 935 ~~~~~~~~~~~~~ 936 937 * Default widget: ``TextInput`` 938 * Empty value: ``None`` 939 * Normalizes to: A Python ``datetime.date`` object. 940 * Validates that the given value is either a ``datetime.date``, 941 ``datetime.datetime`` or string formatted in a particular date format. 942 943 Takes one optional argument, ``input_formats``, which is a list of formats used 944 to attempt to convert a string to a valid ``datetime.date`` object. 945 946 If no ``input_formats`` argument is provided, the default input formats are:: 947 948 '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' 949 '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006' 950 '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006' 951 '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006' 952 '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006' 953 954 ``DateTimeField``&nbs
