mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +00:00 
			
		
		
		
	boulder-oracle-sprint: Merged to [5234]
git-svn-id: http://code.djangoproject.com/svn/django/branches/boulder-oracle-sprint@5235 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		
							
								
								
									
										2
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								AUTHORS
									
									
									
									
									
								
							| @@ -78,6 +78,7 @@ answer newbie questions, and generally made Django that much better: | ||||
|     flavio.curella@gmail.com | ||||
|     Jure Cuhalev <gandalf@owca.info> | ||||
|     dackze+django@gmail.com | ||||
|     David Danier <goliath.mailinglist@gmx.de> | ||||
|     Dirk Datzert <dummy@habmalnefrage.de> | ||||
|     Jonathan Daugherty (cygnus) <http://www.cprogrammer.org/> | ||||
|     dave@thebarproject.com | ||||
| @@ -85,6 +86,7 @@ answer newbie questions, and generally made Django that much better: | ||||
|     Alex Dedul | ||||
|     deric@monowerks.com | ||||
|     Max Derkachev <mderk@yandex.ru> | ||||
|     Jordan Dimov <s3x3y1@gmail.com> | ||||
|     dne@mayonnaise.net | ||||
|     Maximillian Dornseif <md@hudora.de> | ||||
|     Jeremy Dunck <http://dunck.us/> | ||||
|   | ||||
| @@ -38,6 +38,7 @@ LANGUAGE_CODE = 'en-us' | ||||
| LANGUAGES = ( | ||||
|     ('ar', gettext_noop('Arabic')), | ||||
|     ('bn', gettext_noop('Bengali')), | ||||
|     ('bg', gettext_noop('Bulgarian')), | ||||
|     ('ca', gettext_noop('Catalan')), | ||||
|     ('cs', gettext_noop('Czech')), | ||||
|     ('cy', gettext_noop('Welsh')), | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								django/conf/locale/bg/LC_MESSAGES/django.mo
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								django/conf/locale/bg/LC_MESSAGES/django.mo
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2670
									
								
								django/conf/locale/bg/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2670
									
								
								django/conf/locale/bg/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								django/conf/locale/bg/LC_MESSAGES/djangojs.mo
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								django/conf/locale/bg/LC_MESSAGES/djangojs.mo
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										106
									
								
								django/conf/locale/bg/LC_MESSAGES/djangojs.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								django/conf/locale/bg/LC_MESSAGES/djangojs.po
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| # translation of djangojs.po to Bulgarian | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: djangojs\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2005-12-09 11:51+0100\n" | ||||
| "PO-Revision-Date: 2007-05-12 17:51+0300\n" | ||||
| "Last-Translator: Jordan Dimov <s3x3y1@gmail.com>\n" | ||||
| "Language-Team: Bulgarian\n" | ||||
| "MIME-Version: 1.0\n" | ||||
| "Content-Type: text/plain; charset=UTF-8\n" | ||||
| "Content-Transfer-Encoding: 8bit\n" | ||||
|  | ||||
| #: contrib/admin/media/js/SelectFilter2.js:33 | ||||
| #, perl-format | ||||
| msgid "Available %s" | ||||
| msgstr "Налични %s" | ||||
|  | ||||
| #: contrib/admin/media/js/SelectFilter2.js:41 | ||||
| msgid "Choose all" | ||||
| msgstr "Избери всички" | ||||
|  | ||||
| #: contrib/admin/media/js/SelectFilter2.js:46 | ||||
| msgid "Add" | ||||
| msgstr "Добави" | ||||
|  | ||||
| #: contrib/admin/media/js/SelectFilter2.js:48 | ||||
| msgid "Remove" | ||||
| msgstr "Премахни" | ||||
|  | ||||
| #: contrib/admin/media/js/SelectFilter2.js:53 | ||||
| #, perl-format | ||||
| msgid "Chosen %s" | ||||
| msgstr "Избрахме %s" | ||||
|  | ||||
| #: contrib/admin/media/js/SelectFilter2.js:54 | ||||
| msgid "Select your choice(s) and click " | ||||
| msgstr "Направете своя избор и щракнете " | ||||
|  | ||||
| #: contrib/admin/media/js/SelectFilter2.js:59 | ||||
| msgid "Clear all" | ||||
| msgstr "Изчисти всички" | ||||
|  | ||||
| #: contrib/admin/media/js/dateparse.js:26 | ||||
| #: contrib/admin/media/js/calendar.js:24 | ||||
| msgid "" | ||||
| "January February March April May June July August September October November " | ||||
| "December" | ||||
| msgstr "Януари Февруари Март Април Май Юни Юли Август Септември Октомври Ноември Декември" | ||||
|  | ||||
| #: contrib/admin/media/js/dateparse.js:27 | ||||
| msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday" | ||||
| msgstr "Неделя Понеделник Вторник Сряда Четвъртък Петък Събота" | ||||
|  | ||||
| #: contrib/admin/media/js/calendar.js:25 | ||||
| msgid "S M T W T F S" | ||||
| msgstr "Н П В С Ч П С" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:45 | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:80 | ||||
| msgid "Now" | ||||
| msgstr "Сега" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:48 | ||||
| msgid "Clock" | ||||
| msgstr "Часовник" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:77 | ||||
| msgid "Choose a time" | ||||
| msgstr "Избери време" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:81 | ||||
| msgid "Midnight" | ||||
| msgstr "Полунощ" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:82 | ||||
| msgid "6 a.m." | ||||
| msgstr "6 a.m." | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:83 | ||||
| msgid "Noon" | ||||
| msgstr "По обяд" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:87 | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:168 | ||||
| msgid "Cancel" | ||||
| msgstr "Отказ" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:111 | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:162 | ||||
| msgid "Today" | ||||
| msgstr "Днес" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:114 | ||||
| msgid "Calendar" | ||||
| msgstr "Календар" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:160 | ||||
| msgid "Yesterday" | ||||
| msgstr "Вчера" | ||||
|  | ||||
| #: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 | ||||
| msgid "Tomorrow" | ||||
| msgstr "Утре" | ||||
|  | ||||
| @@ -41,7 +41,7 @@ class ISIdNumberField(RegexField): | ||||
|         method is modulo 11. | ||||
|         """ | ||||
|         check = [3, 2, 7, 6, 5, 4, 3, 2, 1, 0] | ||||
|         return sum(int(value[i]) * check[i] for i in range(10)) % 11 == 0 | ||||
|         return sum([int(value[i]) * check[i] for i in range(10)]) % 11 == 0 | ||||
|  | ||||
|     def _format(self, value): | ||||
|         """ | ||||
|   | ||||
| @@ -1463,20 +1463,24 @@ def load_data(fixture_labels, verbosity=1): | ||||
|                     if verbosity > 1: | ||||
|                         print "No %s fixture '%s' in %s." % \ | ||||
|                             (format, fixture_name, humanize(fixture_dir)) | ||||
|     if count[0] == 0: | ||||
|         if verbosity > 0: | ||||
|             print "No fixtures found." | ||||
|     else: | ||||
|         if verbosity > 0: | ||||
|             print "Installed %d object(s) from %d fixture(s)" % tuple(count) | ||||
|                              | ||||
|     if count[0] > 0: | ||||
|         sequence_sql = backend.get_sql_sequence_reset(style, models) | ||||
|         if sequence_sql: | ||||
|             if verbosity > 1: | ||||
|                 print "Resetting sequences" | ||||
|             for line in sequence_sql: | ||||
|                 cursor.execute(line) | ||||
|              | ||||
|     transaction.commit() | ||||
|     transaction.leave_transaction_management() | ||||
|      | ||||
|     if count[0] == 0: | ||||
|         if verbosity > 0: | ||||
|             print "No fixtures found." | ||||
|     else: | ||||
|         if verbosity > 0: | ||||
|             print "Installed %d object(s) from %d fixture(s)" % tuple(count) | ||||
|  | ||||
| load_data.help_doc = 'Installs the named fixture(s) in the database' | ||||
| load_data.args = "[--verbosity] fixture, fixture, ..." | ||||
|   | ||||
| @@ -37,7 +37,7 @@ class Serializer(base.Serializer): | ||||
|     def handle_fk_field(self, obj, field): | ||||
|         related = getattr(obj, field.name) | ||||
|         if related is not None: | ||||
|             related = related._get_pk_val() | ||||
|             related = getattr(related, field.rel.field_name) | ||||
|         self._current[field.name] = related | ||||
|      | ||||
|     def handle_m2m_field(self, obj, field): | ||||
| @@ -80,7 +80,10 @@ def Deserializer(object_list, **options): | ||||
|                  | ||||
|             # Handle FK fields | ||||
|             elif field.rel and isinstance(field.rel, models.ManyToOneRel): | ||||
|                 data[field.attname] = field.rel.to._meta.pk.to_python(field_value) | ||||
|                 if field_value: | ||||
|                     data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value) | ||||
|                 else: | ||||
|                     data[field.attname] = None | ||||
|                      | ||||
|             # Handle all other fields | ||||
|             else: | ||||
|   | ||||
| @@ -82,7 +82,7 @@ class Serializer(base.Serializer): | ||||
|         self._start_relational_field(field) | ||||
|         related = getattr(obj, field.name) | ||||
|         if related is not None: | ||||
|             self.xml.characters(str(related._get_pk_val())) | ||||
|             self.xml.characters(str(getattr(related, field.rel.field_name))) | ||||
|         else: | ||||
|             self.xml.addQuickElement("None") | ||||
|         self.xml.endElement("field") | ||||
| @@ -181,7 +181,7 @@ class Deserializer(base.Deserializer): | ||||
|         if len(node.childNodes) == 1 and node.childNodes[0].nodeName == 'None': | ||||
|             return None | ||||
|         else: | ||||
|             return field.rel.to._meta.pk.to_python( | ||||
|             return field.rel.to._meta.get_field(field.rel.field_name).to_python( | ||||
|                        getInnerText(node).strip().encode(self.encoding)) | ||||
|          | ||||
|     def _handle_m2m_field_node(self, node, field): | ||||
|   | ||||
| @@ -242,7 +242,7 @@ def get_sql_sequence_reset(style, model_list): | ||||
|             if isinstance(f, models.AutoField): | ||||
|                 output.append("%s setval('%s', (%s max(%s) %s %s));" % \ | ||||
|                     (style.SQL_KEYWORD('SELECT'), | ||||
|                     style.SQL_FIELD('%s_%s_seq' % (model._meta.db_table, f.column)), | ||||
|                     style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), | ||||
|                     style.SQL_KEYWORD('SELECT'), | ||||
|                     style.SQL_FIELD(quote_name(f.column)), | ||||
|                     style.SQL_KEYWORD('FROM'), | ||||
| @@ -251,7 +251,7 @@ def get_sql_sequence_reset(style, model_list): | ||||
|         for f in model._meta.many_to_many: | ||||
|             output.append("%s setval('%s', (%s max(%s) %s %s));" % \ | ||||
|                 (style.SQL_KEYWORD('SELECT'), | ||||
|                 style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()), | ||||
|                 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), | ||||
|                 style.SQL_KEYWORD('SELECT'), | ||||
|                 style.SQL_FIELD(quote_name('id')), | ||||
|                 style.SQL_KEYWORD('FROM'), | ||||
|   | ||||
| @@ -199,7 +199,7 @@ def get_sql_sequence_reset(style, model_list): | ||||
|             if isinstance(f, models.AutoField): | ||||
|                 output.append("%s setval('%s', (%s max(%s) %s %s));" % \ | ||||
|                     (style.SQL_KEYWORD('SELECT'), | ||||
|                     style.SQL_FIELD('%s_%s_seq' % (model._meta.db_table, f.column)), | ||||
|                     style.SQL_FIELD(quote_name('%s_%s_seq' % (model._meta.db_table, f.column))), | ||||
|                     style.SQL_KEYWORD('SELECT'), | ||||
|                     style.SQL_FIELD(quote_name(f.column)), | ||||
|                     style.SQL_KEYWORD('FROM'), | ||||
| @@ -208,7 +208,7 @@ def get_sql_sequence_reset(style, model_list): | ||||
|         for f in model._meta.many_to_many: | ||||
|             output.append("%s setval('%s', (%s max(%s) %s %s));" % \ | ||||
|                 (style.SQL_KEYWORD('SELECT'), | ||||
|                 style.SQL_FIELD('%s_id_seq' % f.m2m_db_table()), | ||||
|                 style.SQL_FIELD(quote_name('%s_id_seq' % f.m2m_db_table())), | ||||
|                 style.SQL_KEYWORD('SELECT'), | ||||
|                 style.SQL_FIELD(quote_name('id')), | ||||
|                 style.SQL_KEYWORD('FROM'), | ||||
|   | ||||
| @@ -184,8 +184,8 @@ class BaseForm(StrAndUnicode): | ||||
|             try: | ||||
|                 value = field.clean(value) | ||||
|                 self.clean_data[name] = value | ||||
|                 if hasattr(self, 'clean_%s' % name): | ||||
|                     value = getattr(self, 'clean_%s' % name)() | ||||
|                 if hasattr(self, 'do_clean_%s' % name): | ||||
|                     value = getattr(self, 'do_clean_%s' % name)() | ||||
|                 self.clean_data[name] = value | ||||
|             except ValidationError, e: | ||||
|                 errors[name] = e.messages | ||||
| @@ -255,6 +255,8 @@ class BoundField(StrAndUnicode): | ||||
|             attrs['id'] = auto_id | ||||
|         if not self.form.is_bound: | ||||
|             data = self.form.initial.get(self.name, self.field.initial) | ||||
|             if callable(data): | ||||
|                 data = data() | ||||
|         else: | ||||
|             data = self.data | ||||
|         return widget.render(self.html_name, data, attrs=attrs) | ||||
|   | ||||
| @@ -12,17 +12,7 @@ from widgets import Select, SelectMultiple, MultipleHiddenInput | ||||
| __all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields', | ||||
|            'ModelChoiceField', 'ModelMultipleChoiceField') | ||||
|  | ||||
| def model_save(self, commit=True): | ||||
|     """ | ||||
|     Creates and returns model instance according to self.clean_data. | ||||
|  | ||||
|     This method is created for any form_for_model Form. | ||||
|     """ | ||||
|     if self.errors: | ||||
|         raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name) | ||||
|     return save_instance(self, self._model(), commit) | ||||
|  | ||||
| def save_instance(form, instance, commit=True): | ||||
| def save_instance(form, instance, fields=None, fail_message='saved', commit=True): | ||||
|     """ | ||||
|     Saves bound Form ``form``'s clean_data into model instance ``instance``. | ||||
|  | ||||
| @@ -33,15 +23,19 @@ def save_instance(form, instance, commit=True): | ||||
|     from django.db import models | ||||
|     opts = instance.__class__._meta | ||||
|     if form.errors: | ||||
|         raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name) | ||||
|         raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message)) | ||||
|     clean_data = form.clean_data | ||||
|     for f in opts.fields: | ||||
|         if not f.editable or isinstance(f, models.AutoField) or not f.name in clean_data: | ||||
|             continue | ||||
|         if fields and f.name not in fields: | ||||
|             continue | ||||
|         setattr(instance, f.name, clean_data[f.name]) | ||||
|     if commit: | ||||
|         instance.save() | ||||
|         for f in opts.many_to_many: | ||||
|             if fields and f.name not in fields: | ||||
|                 continue | ||||
|             if f.name in clean_data: | ||||
|                 setattr(instance, f.attname, clean_data[f.name]) | ||||
|     # GOTCHA: If many-to-many data is given and commit=False, the many-to-many | ||||
| @@ -50,13 +44,19 @@ def save_instance(form, instance, commit=True): | ||||
|     # exception in that case. | ||||
|     return instance | ||||
|  | ||||
| def make_instance_save(instance): | ||||
|     "Returns the save() method for a form_for_instance Form." | ||||
| def make_model_save(model, fields, fail_message): | ||||
|     "Returns the save() method for a Form." | ||||
|     def save(self, commit=True): | ||||
|         return save_instance(self, instance, commit) | ||||
|         return save_instance(self, model(), fields, fail_message, commit) | ||||
|     return save | ||||
|      | ||||
| def make_instance_save(instance, fields, fail_message): | ||||
|     "Returns the save() method for a Form." | ||||
|     def save(self, commit=True): | ||||
|         return save_instance(self, instance, fields, fail_message, commit) | ||||
|     return save | ||||
|  | ||||
| def form_for_model(model, form=BaseForm, formfield_callback=lambda f: f.formfield()): | ||||
| def form_for_model(model, form=BaseForm, fields=None, formfield_callback=lambda f: f.formfield()): | ||||
|     """ | ||||
|     Returns a Form class for the given Django model class. | ||||
|  | ||||
| @@ -71,13 +71,16 @@ def form_for_model(model, form=BaseForm, formfield_callback=lambda f: f.formfiel | ||||
|     for f in opts.fields + opts.many_to_many: | ||||
|         if not f.editable: | ||||
|             continue | ||||
|         if fields and not f.name in fields: | ||||
|             continue | ||||
|         formfield = formfield_callback(f) | ||||
|         if formfield: | ||||
|             field_list.append((f.name, formfield)) | ||||
|     fields = SortedDictFromList(field_list) | ||||
|     return type(opts.object_name + 'Form', (form,), {'base_fields': fields, '_model': model, 'save': model_save}) | ||||
|     base_fields = SortedDictFromList(field_list) | ||||
|     return type(opts.object_name + 'Form', (form,),  | ||||
|         {'base_fields': base_fields, '_model': model, 'save': make_model_save(model, fields, 'created')}) | ||||
|  | ||||
| def form_for_instance(instance, form=BaseForm, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)): | ||||
| def form_for_instance(instance, form=BaseForm, fields=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)): | ||||
|     """ | ||||
|     Returns a Form class for the given Django model instance. | ||||
|  | ||||
| @@ -94,13 +97,15 @@ def form_for_instance(instance, form=BaseForm, formfield_callback=lambda f, **kw | ||||
|     for f in opts.fields + opts.many_to_many: | ||||
|         if not f.editable: | ||||
|             continue | ||||
|         if fields and not f.name in fields: | ||||
|             continue | ||||
|         current_value = f.value_from_object(instance) | ||||
|         formfield = formfield_callback(f, initial=current_value) | ||||
|         if formfield: | ||||
|             field_list.append((f.name, formfield)) | ||||
|     fields = SortedDictFromList(field_list) | ||||
|     base_fields = SortedDictFromList(field_list) | ||||
|     return type(opts.object_name + 'InstanceForm', (form,), | ||||
|         {'base_fields': fields, '_model': model, 'save': make_instance_save(instance)}) | ||||
|         {'base_fields': base_fields, '_model': model, 'save': make_instance_save(instance, fields, 'changed')}) | ||||
|  | ||||
| def form_for_fields(field_list): | ||||
|     "Returns a Form class for the given list of Django database field instances." | ||||
|   | ||||
| @@ -45,16 +45,16 @@ class TestCase(unittest.TestCase): | ||||
|         if hasattr(self, 'fixtures'): | ||||
|             management.load_data(self.fixtures, verbosity=0) | ||||
|         mail.outbox = [] | ||||
|          | ||||
|     def run(self, result=None): | ||||
|         """Wrapper around default run method to perform common Django test set up. | ||||
|         This means that user-defined Test Cases aren't required to include a call  | ||||
|         to super().setUp(). | ||||
|          | ||||
|  | ||||
|     def __call__(self, result=None): | ||||
|         """ | ||||
|         Wrapper around default __call__ method to perform common Django test | ||||
|         set up. This means that user-defined Test Cases aren't required to | ||||
|         include a call to super().setUp(). | ||||
|         """ | ||||
|         self.client = Client() | ||||
|         self._pre_setup() | ||||
|         super(TestCase, self).run(result) | ||||
|         super(TestCase, self).__call__(result) | ||||
|  | ||||
|     def assertRedirects(self, response, expected_path, status_code=302, target_status_code=200): | ||||
|         """Assert that a response redirected to a specific URL, and that the | ||||
| @@ -62,7 +62,7 @@ class TestCase(unittest.TestCase): | ||||
|          | ||||
|         """ | ||||
|         self.assertEqual(response.status_code, status_code,  | ||||
|             "Response didn't redirect: Reponse code was %d (expected %d)" %  | ||||
|             "Response didn't redirect as expected: Reponse code was %d (expected %d)" %  | ||||
|                 (response.status_code, status_code)) | ||||
|         scheme, netloc, path, params, query, fragment = urlparse(response['Location']) | ||||
|         self.assertEqual(path, expected_path,  | ||||
| @@ -70,7 +70,7 @@ class TestCase(unittest.TestCase): | ||||
|         redirect_response = self.client.get(path) | ||||
|         self.assertEqual(redirect_response.status_code, target_status_code,  | ||||
|             "Couldn't retrieve redirection page '%s': response code was %d (expected %d)" %  | ||||
|                 (path, response.status_code, status_code)) | ||||
|                 (path, redirect_response.status_code, target_status_code)) | ||||
|      | ||||
|     def assertContains(self, response, text, count=1, status_code=200): | ||||
|         """Assert that a response indicates that a page was retreived successfully, | ||||
| @@ -108,7 +108,7 @@ class TestCase(unittest.TestCase): | ||||
|                 for err in errors: | ||||
|                     if field: | ||||
|                         if field in context[form].errors: | ||||
|                             self.assertTrue(err in context[form].errors[field],  | ||||
|                             self.failUnless(err in context[form].errors[field],  | ||||
|                             "The field '%s' on form '%s' in context %d does not contain the error '%s' (actual errors: %s)" %  | ||||
|                                 (field, form, i, err, list(context[form].errors[field]))) | ||||
|                         elif field in context[form].fields: | ||||
| @@ -117,7 +117,7 @@ class TestCase(unittest.TestCase): | ||||
|                         else: | ||||
|                             self.fail("The form '%s' in context %d does not contain the field '%s'" % (form, i, field)) | ||||
|                     else: | ||||
|                         self.assertTrue(err in context[form].non_field_errors(),  | ||||
|                         self.failUnless(err in context[form].non_field_errors(),  | ||||
|                             "The form '%s' in context %d does not contain the non-field error '%s' (actual errors: %s)" %  | ||||
|                                 (form, i, err, list(context[form].non_field_errors()))) | ||||
|         if not found_form: | ||||
| @@ -127,7 +127,7 @@ class TestCase(unittest.TestCase): | ||||
|         "Assert that the template with the provided name was used in rendering the response" | ||||
|         if isinstance(response.template, list): | ||||
|             template_names = [t.name for t in response.template] | ||||
|             self.assertTrue(template_name in template_names, | ||||
|             self.failUnless(template_name in template_names, | ||||
|                 "Template '%s' was not one of the templates used to render the response. Templates used: %s" % | ||||
|                     (template_name, template_names)) | ||||
|         elif response.template: | ||||
| @@ -140,9 +140,9 @@ class TestCase(unittest.TestCase): | ||||
|     def assertTemplateNotUsed(self, response, template_name): | ||||
|         "Assert that the template with the provided name was NOT used in rendering the response" | ||||
|         if isinstance(response.template, list):             | ||||
|             self.assertFalse(template_name in [t.name for t in response.template], | ||||
|             self.failIf(template_name in [t.name for t in response.template], | ||||
|                 "Template '%s' was used unexpectedly in rendering the response" % template_name) | ||||
|         elif response.template: | ||||
|             self.assertNotEqual(template_name, response.template.name, | ||||
|                 "Template '%s' was used unexpectedly in rendering the response" % template_name) | ||||
|          | ||||
|          | ||||
|   | ||||
| @@ -44,7 +44,11 @@ How to use Databrowse | ||||
|        It doesn't matter where you put this, as long as it gets executed at | ||||
|        some point. A good place for it is in your URLconf file (``urls.py``). | ||||
|  | ||||
|     3. Add the following line to your URLconf:: | ||||
|     3. Change your URLconf to import the ``databrowse`` module:: | ||||
|  | ||||
|            from django.contrib import databrowse | ||||
|  | ||||
|        ...and add the following line to your URLconf:: | ||||
|  | ||||
|            (r'^databrowse/(.*)', databrowse.site.root), | ||||
|  | ||||
|   | ||||
| @@ -236,7 +236,7 @@ To pluralize, specify both the singular and plural forms with the | ||||
| ``{% plural %}`` tag, which appears within ``{% blocktrans %}`` and | ||||
| ``{% endblocktrans %}``. Example:: | ||||
|  | ||||
|     {% blocktrans count list|count as counter %} | ||||
|     {% blocktrans count list|length as counter %} | ||||
|     There is only one {{ name }} object. | ||||
|     {% plural %} | ||||
|     There are {{ counter }} {{ name }} objects. | ||||
|   | ||||
| @@ -9,28 +9,30 @@ framework. This document explains how to use this new library. | ||||
| Migration plan | ||||
| ============== | ||||
|  | ||||
| ``django.newforms`` currently is only available in Django beginning | ||||
| with the 0.96 release.  the Django development version -- i.e., it's | ||||
| not available in the Django 0.95 release. For the next Django release, | ||||
| our plan is to do the following: | ||||
| ``django.newforms`` is new in Django's 0.96 release, but, as it won't be new | ||||
| forever, we plan to rename it to ``django.forms`` in the future. The current | ||||
| ``django.forms`` package will be available as ``django.oldforms`` until Django | ||||
| 1.0, when we plan to remove it for good. | ||||
|  | ||||
|     * As of revision [4208], we've copied the current ``django.forms`` to | ||||
|       ``django.oldforms``. This allows you to upgrade your code *now* rather | ||||
|       than waiting for the backwards-incompatible change and rushing to fix | ||||
|       your code after the fact. Just change your import statements like this:: | ||||
| That has direct repercussions on the forward compatibility of your code. Please | ||||
| read the following migration plan and code accordingly: | ||||
|  | ||||
|     * The old forms framework (the current ``django.forms``) has been copied to | ||||
|       ``django.oldforms``. Thus, you can start upgrading your code *now*, | ||||
|       rather than waiting for the future backwards-incompatible change, by | ||||
|       changing your import statements like this:: | ||||
|  | ||||
|           from django import forms             # old | ||||
|           from django import oldforms as forms # new | ||||
|  | ||||
|     * At an undecided future date, we will move the current ``django.newforms`` | ||||
|       to ``django.forms``. This will be a backwards-incompatible change, and | ||||
|       anybody who is still using the old version of ``django.forms`` at that | ||||
|       time will need to change their import statements, as described in the | ||||
|       previous bullet. | ||||
|     * In the next Django release (0.97), we will move the current | ||||
|       ``django.newforms`` to ``django.forms``. This will be a | ||||
|       backwards-incompatible change, and anybody who is still using the old | ||||
|       version of ``django.forms`` at that time will need to change their import | ||||
|       statements, as described in the previous bullet. | ||||
|  | ||||
|     * We will remove ``django.oldforms`` in the release *after* the next Django | ||||
|       release -- the release that comes after the release in which we're | ||||
|       creating the new ``django.forms``. | ||||
|       release -- either 0.98 or 1.0, whichever comes first. | ||||
|  | ||||
| With this in mind, we recommend you use the following import statement when | ||||
| using ``django.newforms``:: | ||||
| @@ -184,7 +186,7 @@ e-mail address:: | ||||
|     >>> f.is_valid() | ||||
|     False | ||||
|  | ||||
| Access the ``Form`` attribute ``errors`` to get a dictionary of error messages:: | ||||
| Access the ``errors`` attribute to get a dictionary of error messages:: | ||||
|  | ||||
|     >>> f.errors | ||||
|     {'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']} | ||||
| @@ -197,6 +199,10 @@ You can access ``errors`` without having to call ``is_valid()`` first. The | ||||
| form's data will be validated the first time either you call ``is_valid()`` or | ||||
| access ``errors``. | ||||
|  | ||||
| The validation routines will only get called once, regardless of how many times | ||||
| you access ``errors`` or call ``is_valid()``. This means that if validation has | ||||
| side effects, those side effects will only be triggered once. | ||||
|  | ||||
| Behavior of unbound forms | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| @@ -274,6 +280,27 @@ but ``clean_data`` contains only the form's fields:: | ||||
|     >>> f.clean_data # Doesn't contain extra_field_1, etc. | ||||
|     {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} | ||||
|  | ||||
| ``clean_data`` will include a key and value for *all* fields defined in the | ||||
| ``Form``, even if the data didn't include a value for fields that are not | ||||
| required. In this example, the data dictionary doesn't include a value for the | ||||
| ``nick_name`` field, but ``clean_data`` includes it, with an empty value:: | ||||
|  | ||||
|     >>> class OptionalPersonForm(Form): | ||||
|     ...     first_name = CharField() | ||||
|     ...     last_name = CharField() | ||||
|     ...     nick_name = CharField(required=False) | ||||
|     >>> data = {'first_name': u'John', 'last_name': u'Lennon'} | ||||
|     >>> f = OptionalPersonForm(data) | ||||
|     >>> f.is_valid() | ||||
|     True | ||||
|     >>> f.clean_data | ||||
|     {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} | ||||
|  | ||||
| In this above example, the ``clean_data`` value for ``nick_name`` is set to an | ||||
| empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat | ||||
| empty values as an empty string. Each field type knows what its "blank" value | ||||
| is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. | ||||
|  | ||||
| Behavior of unbound forms | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| @@ -454,7 +481,7 @@ field:: | ||||
| If ``auto_id`` is set to a string containing the format character ``'%s'``, | ||||
| then the form output will include ``<label>`` tags, and will generate ``id`` | ||||
| attributes based on the format string. For example, for a format string | ||||
| ``'field_%s'``, a field named ``subject`` will get the ``id`` | ||||
| ``'field_%s'``, a field named ``subject`` will get the ``id`` value | ||||
| ``'field_subject'``. Continuing our example:: | ||||
|  | ||||
|     >>> f = ContactForm(auto_id='id_for_%s') | ||||
| @@ -493,8 +520,9 @@ How errors are displayed | ||||
|  | ||||
| If you render a bound ``Form`` object, the act of rendering will automatically | ||||
| run the form's validation if it hasn't already happened, and the HTML output | ||||
| will include the validation errors as a ``<ul>`` near the field. The particular | ||||
| positioning of the error messages depends on the output method you're using:: | ||||
| will include the validation errors as a ``<ul class="errorlist">`` near the | ||||
| field. The particular positioning of the error messages depends on the output | ||||
| method you're using:: | ||||
|  | ||||
|     >>> data = {'subject': '', | ||||
|     ...         'message': 'Hi there', | ||||
| @@ -556,7 +584,8 @@ The field-specific output honors the form object's ``auto_id`` setting:: | ||||
|     <input type="text" name="message" id="id_message" /> | ||||
|  | ||||
| For a field's list of errors, access the field's ``errors`` attribute. This | ||||
| is a list-like object that is displayed as an HTML ``<ul>`` when printed:: | ||||
| is a list-like object that is displayed as an HTML ``<ul class="errorlist">`` | ||||
| when printed:: | ||||
|  | ||||
|     >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} | ||||
|     >>> f = ContactForm(data, auto_id=False) | ||||
| @@ -646,7 +675,7 @@ Core field arguments | ||||
|  | ||||
| Each ``Field`` class constructor takes at least these arguments. Some | ||||
| ``Field`` classes take additional, field-specific arguments, but the following | ||||
| should *always* be available: | ||||
| should *always* be accepted: | ||||
|  | ||||
| ``required`` | ||||
| ~~~~~~~~~~~~ | ||||
| @@ -704,7 +733,7 @@ field.) | ||||
| The ``label`` argument lets you specify the "human-friendly" label for this | ||||
| field. This is used when the ``Field`` is displayed in a ``Form``. | ||||
|  | ||||
| As explained in _`Outputting forms as HTML` above, the default label for a | ||||
| As explained in "Outputting forms as HTML" above, the default label for a | ||||
| ``Field`` is generated from the field name by converting all underscores to | ||||
| spaces and upper-casing the first letter. Specify ``label`` if that default | ||||
| behavior doesn't result in an adequate label. | ||||
| @@ -779,14 +808,15 @@ validation if a particular field's value is not given. ``initial`` values are | ||||
| ~~~~~~~~~~ | ||||
|  | ||||
| The ``widget`` argument lets you specify a ``Widget`` class to use when | ||||
| rendering this ``Field``. See _`Widgets` below for more information. | ||||
| rendering this ``Field``. See "Widgets" below for more information. | ||||
|  | ||||
| ``help_text`` | ||||
| ~~~~~~~~~~~~~ | ||||
|  | ||||
| The ``help_text`` argument lets you specify descriptive text for this | ||||
| ``Field``. If you provide ``help_text``, it will be displayed next to the | ||||
| ``Field`` when the ``Field`` is rendered in a ``Form``. | ||||
| ``Field`` when the ``Field`` is rendered by one of the convenience ``Form`` | ||||
| methods (e.g., ``as_ul()``). | ||||
|  | ||||
| Here's a full example ``Form`` that implements ``help_text`` for two of its | ||||
| fields. We've specified ``auto_id=False`` to simplify the output:: | ||||
| @@ -860,6 +890,212 @@ level and at the form instance level, and the latter gets precedence:: | ||||
|     <tr><th>Url:</th><td><input type="text" name="url" /></td></tr> | ||||
|     <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> | ||||
|  | ||||
| Built-in ``Field`` classes | ||||
| -------------------------- | ||||
|  | ||||
| Naturally, the ``newforms`` library comes with a set of ``Field`` classes that | ||||
| represent common validation needs. This section documents each built-in field. | ||||
|  | ||||
| For each field, we describe the default widget used if you don't specify | ||||
| ``widget``. We also specify the value returned when you provide an empty value | ||||
| (see the section on ``required`` above to understand what that means). | ||||
|  | ||||
| ``BooleanField`` | ||||
| ~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``CheckboxInput`` | ||||
|     * Empty value: ``None`` | ||||
|     * Normalizes to: A Python ``True`` or ``False`` value. | ||||
|     * Validates nothing (i.e., it never raises a ``ValidationError``). | ||||
|  | ||||
| ``CharField`` | ||||
| ~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``''`` (an empty string) | ||||
|     * Normalizes to: A Unicode object. | ||||
|     * Validates nothing, unless ``max_length`` or ``min_length`` is provided. | ||||
|  | ||||
| Has two optional arguments for validation, ``max_length`` and ``min_length``. | ||||
| If provided, these arguments ensure that the string is at most or at least the | ||||
| given length. | ||||
|  | ||||
| ``ChoiceField`` | ||||
| ~~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``Select`` | ||||
|     * Empty value: ``''`` (an empty string) | ||||
|     * Normalizes to: A Unicode object. | ||||
|     * Validates that the given value exists in the list of choices. | ||||
|  | ||||
| Takes one extra argument, ``choices``, which is an iterable (e.g., a list or | ||||
| tuple) of 2-tuples to use as choices for this field. | ||||
|  | ||||
| ``DateField`` | ||||
| ~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``None`` | ||||
|     * Normalizes to: A Python ``datetime.date`` object. | ||||
|     * Validates that the given value is either a ``datetime.date``, | ||||
|       ``datetime.datetime`` or string formatted in a particular date format. | ||||
|  | ||||
| Takes one optional argument, ``input_formats``, which is a list of formats used | ||||
| to attempt to convert a string to a valid ``datetime.date`` object. | ||||
|  | ||||
| If no ``input_formats`` argument is provided, the default input formats are:: | ||||
|  | ||||
|     '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06' | ||||
|     '%b %d %Y', '%b %d, %Y',            # 'Oct 25 2006', 'Oct 25, 2006' | ||||
|     '%d %b %Y', '%d %b, %Y',            # '25 Oct 2006', '25 Oct, 2006' | ||||
|     '%B %d %Y', '%B %d, %Y',            # 'October 25 2006', 'October 25, 2006' | ||||
|     '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006' | ||||
|  | ||||
| ``DateTimeField`` | ||||
| ~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``None`` | ||||
|     * Normalizes to: A Python ``datetime.datetime`` object. | ||||
|     * Validates that the given value is either a ``datetime.datetime``, | ||||
|       ``datetime.date`` or string formatted in a particular datetime format. | ||||
|  | ||||
| Takes one optional argument, ``input_formats``, which is a list of formats used | ||||
| to attempt to convert a string to a valid ``datetime.datetime`` object. | ||||
|  | ||||
| If no ``input_formats`` argument is provided, the default input formats are:: | ||||
|  | ||||
|     '%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59' | ||||
|     '%Y-%m-%d %H:%M',        # '2006-10-25 14:30' | ||||
|     '%Y-%m-%d',              # '2006-10-25' | ||||
|     '%m/%d/%Y %H:%M:%S',     # '10/25/2006 14:30:59' | ||||
|     '%m/%d/%Y %H:%M',        # '10/25/2006 14:30' | ||||
|     '%m/%d/%Y',              # '10/25/2006' | ||||
|     '%m/%d/%y %H:%M:%S',     # '10/25/06 14:30:59' | ||||
|     '%m/%d/%y %H:%M',        # '10/25/06 14:30' | ||||
|     '%m/%d/%y',              # '10/25/06' | ||||
|  | ||||
| ``EmailField`` | ||||
| ~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``''`` (an empty string) | ||||
|     * Normalizes to: A Unicode object. | ||||
|     * Validates that the given value is a valid e-mail address, using a | ||||
|       moderately complex regular expression. | ||||
|  | ||||
| Has two optional arguments for validation, ``max_length`` and ``min_length``. | ||||
| If provided, these arguments ensure that the string is at most or at least the | ||||
| given length. | ||||
|  | ||||
| ``IntegerField`` | ||||
| ~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``None`` | ||||
|     * Normalizes to: A Python integer or long integer. | ||||
|     * Validates that the given value is an integer. Leading and trailing | ||||
|       whitespace is allowed, as in Python's ``int()`` function. | ||||
|  | ||||
| ``MultipleChoiceField`` | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``SelectMultiple`` | ||||
|     * Empty value: ``[]`` (an empty list) | ||||
|     * Normalizes to: A list of Unicode objects. | ||||
|     * Validates that every value in the given list of values exists in the list | ||||
|       of choices. | ||||
|  | ||||
| Takes one extra argument, ``choices``, which is an iterable (e.g., a list or | ||||
| tuple) of 2-tuples to use as choices for this field. | ||||
|  | ||||
| ``NullBooleanField`` | ||||
| ~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``NullBooleanSelect`` | ||||
|     * Empty value: ``None`` | ||||
|     * Normalizes to: A Python ``True``, ``False`` or ``None`` value. | ||||
|     * Validates nothing (i.e., it never raises a ``ValidationError``). | ||||
|  | ||||
| ``RegexField`` | ||||
| ~~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``''`` (an empty string) | ||||
|     * Normalizes to: A Unicode object. | ||||
|     * Validates that the given value matches against a certain regular | ||||
|       expression. | ||||
|  | ||||
| Takes one required argument, ``regex``, which is a regular expression specified | ||||
| either as a string or a compiled regular expression object. | ||||
|  | ||||
| Also takes the following optional arguments: | ||||
|  | ||||
|     ======================  ===================================================== | ||||
|     Argument                Description | ||||
|     ======================  ===================================================== | ||||
|     ``max_length``          Ensures the string has at most this many characters. | ||||
|     ``min_length``          Ensures the string has at least this many characters. | ||||
|     ``error_message``       Error message to return for failed validation. If no | ||||
|                             message is provided, a generic error message will be | ||||
|                             used. | ||||
|     ======================  ===================================================== | ||||
|  | ||||
| ``TimeField`` | ||||
| ~~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``None`` | ||||
|     * Normalizes to: A Python ``datetime.time`` object. | ||||
|     * Validates that the given value is either a ``datetime.time`` or string | ||||
|       formatted in a particular time format. | ||||
|  | ||||
| Takes one optional argument, ``input_formats``, which is a list of formats used | ||||
| to attempt to convert a string to a valid ``datetime.time`` object. | ||||
|  | ||||
| If no ``input_formats`` argument is provided, the default input formats are:: | ||||
|  | ||||
|     '%H:%M:%S',     # '14:30:59' | ||||
|     '%H:%M',        # '14:30' | ||||
|  | ||||
| ``URLField`` | ||||
| ~~~~~~~~~~~~ | ||||
|  | ||||
|     * Default widget: ``TextInput`` | ||||
|     * Empty value: ``''`` (an empty string) | ||||
|     * Normalizes to: A Unicode object. | ||||
|     * Validates that the given value is a valid URL. | ||||
|  | ||||
| Takes the following optional arguments: | ||||
|  | ||||
|     ========================  ===================================================== | ||||
|     Argument                  Description | ||||
|     ========================  ===================================================== | ||||
|     ``max_length``            Ensures the string has at most this many characters. | ||||
|     ``min_length``            Ensures the string has at least this many characters. | ||||
|     ``verify_exists``         If ``True``, the validator will attempt to load the | ||||
|                               given URL, raising ``ValidationError`` if the page | ||||
|                               gives a 404. Defaults to ``False``. | ||||
|     ``validator_user_agent``  String used as the user-agent used when checking for | ||||
|                               a URL's existence. Defaults to the value of the | ||||
|                               ``URL_VALIDATOR_USER_AGENT`` setting. | ||||
|     ========================  ===================================================== | ||||
|  | ||||
| Slightly complex built-in ``Field`` classes | ||||
| ------------------------------------------- | ||||
|  | ||||
| The following are not yet documented here. See the unit tests, linked-to from | ||||
| the bottom of this document, for examples of their use. | ||||
|  | ||||
| ``ComboField`` | ||||
| ~~~~~~~~~~~~~~ | ||||
|  | ||||
| ``MultiValueField`` | ||||
| ~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| ``SplitDateTimeField`` | ||||
| ~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| Creating custom fields | ||||
| ---------------------- | ||||
|  | ||||
| @@ -870,6 +1106,308 @@ custom ``Field`` classes. To do this, just create a subclass of | ||||
| mentioned above (``required``, ``label``, ``initial``, ``widget``, | ||||
| ``help_text``). | ||||
|  | ||||
| Generating forms for models | ||||
| =========================== | ||||
|  | ||||
| If you're building a database-driven app, chances are you'll have forms that | ||||
| map closely to Django models. For instance, you might have a ``BlogComment`` | ||||
| model, and you want to create a form that lets people submit comments. In this | ||||
| case, it would be redundant to define the field types in your form, because | ||||
| you've already defined the fields in your model. | ||||
|  | ||||
| For this reason, Django provides a few helper functions that let you create a | ||||
| ``Form`` class from a Django model. | ||||
|  | ||||
| ``form_for_model()`` | ||||
| -------------------- | ||||
|  | ||||
| The method ``django.newforms.form_for_model()`` creates a form based on the | ||||
| definition of a specific model. Pass it the model class, and it will return a | ||||
| ``Form`` class that contains a form field for each model field. | ||||
|  | ||||
| For example:: | ||||
|  | ||||
|     >>> from django.newforms import form_for_model | ||||
|  | ||||
|     # Create the form class. | ||||
|     >>> ArticleForm = form_for_model(Article) | ||||
|  | ||||
|     # Create an empty form instance. | ||||
|     >>> f = ArticleForm() | ||||
|  | ||||
| It bears repeating that ``form_for_model()`` takes the model *class*, not a | ||||
| model instance, and it returns a ``Form`` *class*, not a ``Form`` instance. | ||||
|  | ||||
| Field types | ||||
| ~~~~~~~~~~~ | ||||
|  | ||||
| The generated ``Form`` class will have a form field for every model field. Each | ||||
| model field has a corresponding default form field. For example, a | ||||
| ``CharField`` on a model is represented as a ``CharField`` on a form. A | ||||
| model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is | ||||
| the full list of conversions: | ||||
|  | ||||
|     ===============================  ======================================== | ||||
|     Model field                      Form field | ||||
|     ===============================  ======================================== | ||||
|     ``AutoField``                    Not represented in the form | ||||
|     ``BooleanField``                 ``BooleanField`` | ||||
|     ``CharField``                    ``CharField`` with ``max_length`` set to | ||||
|                                      the model field's ``maxlength`` | ||||
|     ``CommaSeparatedIntegerField``   ``CharField`` | ||||
|     ``DateField``                    ``DateField`` | ||||
|     ``DateTimeField``                ``DateTimeField`` | ||||
|     ``EmailField``                   ``EmailField`` | ||||
|     ``FileField``                    ``CharField`` | ||||
|     ``FilePathField``                ``CharField`` | ||||
|     ``FloatField``                   ``CharField`` | ||||
|     ``ForeignKey``                   ``ModelChoiceField`` (see below) | ||||
|     ``ImageField``                   ``CharField`` | ||||
|     ``IntegerField``                 ``IntegerField`` | ||||
|     ``IPAddressField``               ``CharField`` | ||||
|     ``ManyToManyField``              ``ModelMultipleChoiceField`` (see | ||||
|                                      below) | ||||
|     ``NullBooleanField``             ``CharField`` | ||||
|     ``PhoneNumberField``             ``USPhoneNumberField`` | ||||
|                                      (from ``django.contrib.localflavor.us``) | ||||
|     ``PositiveIntegerField``         ``IntegerField`` | ||||
|     ``PositiveSmallIntegerField``    ``IntegerField`` | ||||
|     ``SlugField``                    ``CharField`` | ||||
|     ``SmallIntegerField``            ``IntegerField`` | ||||
|     ``TextField``                    ``CharField`` with ``widget=Textarea`` | ||||
|     ``TimeField``                    ``TimeField`` | ||||
|     ``URLField``                     ``URLField`` with ``verify_exists`` set | ||||
|                                      to the model field's ``verify_exists`` | ||||
|     ``USStateField``                 ``CharField`` with | ||||
|                                      ``widget=USStateSelect`` | ||||
|                                      (``USStateSelect`` is from | ||||
|                                      ``django.contrib.localflavor.us``) | ||||
|     ``XMLField``                     ``CharField`` with ``widget=Textarea`` | ||||
|     ===============================  ======================================== | ||||
|  | ||||
| As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field | ||||
| types are special cases: | ||||
|  | ||||
|     * ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``, | ||||
|       which is a ``ChoiceField`` whose choices are a model ``QuerySet``. | ||||
|  | ||||
|     * ``ManyToManyField`` is represented by | ||||
|       ``django.newforms.ModelMultipleChoiceField``, which is a | ||||
|       ``MultipleChoiceField`` whose choices are a model ``QuerySet``. | ||||
|  | ||||
| In addition, each generated form field has attributes set as follows: | ||||
|  | ||||
|     * If the model field has ``blank=True``, then ``required`` is set to | ||||
|       ``False`` on the form field. Otherwise, ``required=True``. | ||||
|  | ||||
|     * The form field's ``label`` is set to the ``verbose_name`` of the model | ||||
|       field, with the first character capitalized. | ||||
|  | ||||
|     * The form field's ``help_text`` is set to the ``help_text`` of the model | ||||
|       field. | ||||
|  | ||||
|     * If the model field has ``choices`` set, then the form field's ``widget`` | ||||
|       will be set to ``Select``, with choices coming from the model field's | ||||
|       ``choices``. | ||||
|  | ||||
| Finally, note that you can override the form field used for a given model | ||||
| field. See "Overriding the default field types" below. | ||||
|  | ||||
| A full example | ||||
| ~~~~~~~~~~~~~~ | ||||
|  | ||||
| Consider this set of models:: | ||||
|  | ||||
|     from django.db import models | ||||
|  | ||||
|     TITLE_CHOICES = ( | ||||
|         ('MR', 'Mr.'), | ||||
|         ('MRS', 'Mrs.'), | ||||
|         ('MS', 'Ms.'), | ||||
|     ) | ||||
|  | ||||
|     class Author(models.Model): | ||||
|         name = models.CharField(maxlength=100) | ||||
|         title = models.CharField(maxlength=3, choices=TITLE_CHOICES) | ||||
|         birth_date = models.DateField(blank=True, null=True) | ||||
|  | ||||
|         def __str__(self): | ||||
|             return self.name | ||||
|  | ||||
|     class Book(models.Model): | ||||
|         name = models.CharField(maxlength=100) | ||||
|         authors = models.ManyToManyField(Author) | ||||
|  | ||||
| With these models, a call to ``form_for_model(Author)`` would return a ``Form`` | ||||
| class equivalent to this:: | ||||
|  | ||||
|     class AuthorForm(forms.Form): | ||||
|         name = forms.CharField(max_length=100) | ||||
|         title = forms.CharField(max_length=3, | ||||
|                     widget=forms.Select(choices=TITLE_CHOICES)) | ||||
|         birth_date = forms.DateField(required=False) | ||||
|  | ||||
| A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to | ||||
| this:: | ||||
|  | ||||
|     class BookForm(forms.Form): | ||||
|         name = forms.CharField(max_length=100) | ||||
|         authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) | ||||
|  | ||||
| The ``save()`` method | ||||
| ~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| Every form produced by ``form_for_model()`` also has a ``save()`` method. This | ||||
| method creates and saves a database object from the data bound to the form. For | ||||
| example:: | ||||
|  | ||||
|     # Create a form instance from POST data. | ||||
|     >>> f = ArticleForm(request.POST) | ||||
|  | ||||
|     # Save a new Article object from the form's data. | ||||
|     >>> new_article = f.save() | ||||
|  | ||||
| Note that ``save()`` will raise a ``ValueError`` if the data in the form | ||||
| doesn't validate -- i.e., ``if form.errors``. | ||||
|  | ||||
| Using an alternate base class | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| If you want to add custom methods to the form generated by | ||||
| ``form_for_model()``, write a class that extends ``django.newforms.BaseForm`` | ||||
| and contains your custom methods. Then, use the ``form`` argument to | ||||
| ``form_for_model()`` to tell it to use your custom form as its base class. | ||||
| For example:: | ||||
|  | ||||
|     # Create the new base class. | ||||
|     >>> class MyBase(BaseForm): | ||||
|     ...     def my_method(self): | ||||
|     ...         # Do whatever the method does | ||||
|  | ||||
|     # Create the form class with a different base class. | ||||
|     >>> ArticleForm = form_for_model(Article, form=MyBase) | ||||
|  | ||||
|     # Instantiate the form. | ||||
|     >>> f = ArticleForm() | ||||
|  | ||||
|     # Use the base class method. | ||||
|     >>> f.my_method() | ||||
|  | ||||
| Using a subset of fields on the form | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| **New in Django development version** | ||||
|  | ||||
| In some cases, you may not want all the model fields to appear on the generated | ||||
| form. There are two ways of telling ``form_for_model()`` to use only a subset | ||||
| of the model fields: | ||||
|  | ||||
|     1. Set ``editable=False`` on the model field. As a result, *any* form | ||||
|        created from the model via ``form_for_model()`` will not include that | ||||
|        field. | ||||
|  | ||||
|     2. Use the ``fields`` argument to ``form_for_model()``. This argument, if | ||||
|        given, should be a list of field names to include in the form. | ||||
|  | ||||
|        For example, if you want a form for the ``Author`` model (defined above) | ||||
|        that includes only the ``name`` and ``title`` fields, you would specify | ||||
|        ``fields`` like this:: | ||||
|  | ||||
|            PartialArticleForm = form_for_model(Author, fields=('name', 'title')) | ||||
|  | ||||
| .. note:: | ||||
|  | ||||
|     If you specify ``fields`` when creating a form with ``form_for_model()``, | ||||
|     make sure that the fields that are *not* specified can provide default | ||||
|     values, or are allowed to have a value of ``None``. If a field isn't | ||||
|     specified on a form, the object created from the form can't provide | ||||
|     a value for that attribute, which will prevent the new instance from | ||||
|     being saved. | ||||
|  | ||||
| Overriding the default field types | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| The default field types, as described in the "Field types" table above, are | ||||
| sensible defaults; if you have a ``DateField`` in your model, chances are you'd | ||||
| want that to be represented as a ``DateField`` in your form. But | ||||
| ``form_for_model()`` gives you the flexibility of changing the form field type | ||||
| for a given model field. You do this by specifying a **formfield callback**. | ||||
|  | ||||
| A formfield callback is a function that, when provided with a model field, | ||||
| returns a form field instance. When constructing a form, ``form_for_model()`` | ||||
| asks the formfield callback to provide form field types. | ||||
|  | ||||
| By default, ``form_for_model()`` calls the ``formfield()`` method on the model | ||||
| field:: | ||||
|  | ||||
|     def default_callback(field, **kwargs): | ||||
|         return field.formfield(**kwargs) | ||||
|  | ||||
| The ``kwargs`` are any keyword arguments that might be passed to the form | ||||
| field, such as ``required=True`` or ``label='Foo'``. | ||||
|  | ||||
| For example, if you wanted to use ``MyDateFormField`` for any ``DateField`` | ||||
| field on the model, you could define the callback:: | ||||
|  | ||||
|     >>> def my_callback(field, **kwargs): | ||||
|     ...     if isinstance(field, models.DateField): | ||||
|     ...         return MyDateFormField(**kwargs) | ||||
|     ...     else: | ||||
|     ...         return field.formfield(**kwargs) | ||||
|  | ||||
|     >>> ArticleForm = form_for_model(formfield_callback=my_callback) | ||||
|  | ||||
| Note that your callback needs to handle *all* possible model field types, not | ||||
| just the ones that you want to behave differently to the default. That's why | ||||
| this example has an ``else`` clause that implements the default behavior. | ||||
|  | ||||
| Finding the model associated with a form | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| The model class that was used to construct the form is available | ||||
| using the ``_model`` property of the generated form:: | ||||
|  | ||||
|     >>> ArticleForm = form_for_model(Article) | ||||
|     >>> ArticleForm._model | ||||
|     <class 'myapp.models.Article'> | ||||
|  | ||||
| ``form_for_instance()`` | ||||
| ----------------------- | ||||
|  | ||||
| ``form_for_instance()`` is like ``form_for_model()``, but it takes a model | ||||
| instance instead of a model class:: | ||||
|  | ||||
|     # Create an Author. | ||||
|     >>> a = Author(name='Joe Smith', title='MR', birth_date=None) | ||||
|     >>> a.save() | ||||
|  | ||||
|     # Create a form for this particular Author. | ||||
|     >>> AuthorForm = form_for_instance(a) | ||||
|  | ||||
|     # Instantiate the form. | ||||
|     >>> f = AuthorForm() | ||||
|  | ||||
| When a form created by ``form_for_instance()`` is created, the initial | ||||
| data values for the form fields are drawn from the instance. However, | ||||
| this data is not bound to the form. You will need to bind data to the | ||||
| form before the form can be saved. | ||||
|  | ||||
| When you call ``save()`` on a form created by ``form_for_instance()``, | ||||
| the database instance will be updated. As in ``form_for_model()``, ``save()`` | ||||
| will raise ``ValueError`` if the data doesn't validate. | ||||
|  | ||||
| ``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback`` | ||||
| arguments that behave the same way as they do for ``form_for_model()``. | ||||
|  | ||||
| When should you use ``form_for_model()`` and ``form_for_instance()``? | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be | ||||
| shortcuts for the common case. If you want to create a form whose fields map to | ||||
| more than one model, or a form that contains fields that *aren't* on a model, | ||||
| you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way | ||||
| isn't that difficult, after all. | ||||
|  | ||||
| More coming soon | ||||
| ================ | ||||
|  | ||||
| @@ -880,6 +1418,3 @@ what's possible. | ||||
|  | ||||
| If you're really itching to learn and use this library, please be patient. | ||||
| We're working hard on finishing both the code and documentation. | ||||
|  | ||||
| Widgets | ||||
| ======= | ||||
|   | ||||
| @@ -177,7 +177,7 @@ tools that can be used to establish tests and test conditions. | ||||
|  | ||||
| * `Test Client`_ | ||||
| * `TestCase`_ | ||||
| * `Email services`_ | ||||
| * `E-mail services`_ | ||||
|  | ||||
| Test Client | ||||
| ----------- | ||||
| @@ -459,9 +459,9 @@ Emptying the test outbox | ||||
| **New in Django development version** | ||||
|  | ||||
| At the start of each test case, in addition to installing fixtures, | ||||
| Django clears the contents of the test email outbox. | ||||
| Django clears the contents of the test e-mail outbox. | ||||
|  | ||||
| For more detail on email services during tests, see `Email services`_. | ||||
| For more detail on e-mail services during tests, see `E-mail services`_. | ||||
|  | ||||
| Assertions | ||||
| ~~~~~~~~~~ | ||||
| @@ -502,16 +502,17 @@ that can be useful in testing the behavior of web sites. | ||||
|     Assert that the template with the given name was used in rendering the | ||||
|     response. | ||||
|  | ||||
| Email services | ||||
| -------------- | ||||
| E-mail services | ||||
| --------------- | ||||
|  | ||||
| **New in Django development version** | ||||
|  | ||||
| If your view makes use of the `Django email services`_, you don't really | ||||
| want email to be sent every time you run a test using that view. | ||||
| If your view makes use of the `Django e-mail services`_, you don't really | ||||
| want e-mail to be sent every time you run a test using that view. | ||||
|  | ||||
| When the Django test framework is initialized, it transparently replaces the | ||||
| normal `SMTPConnection`_ class with a dummy implementation that redirects all | ||||
| email to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``, | ||||
| e-mail to a dummy outbox. This outbox, stored as ``django.core.mail.outbox``, | ||||
| is a simple list of all `EmailMessage`_ instances that have been sent. | ||||
| For example, during test conditions, it would be possible to run the following | ||||
| code:: | ||||
| @@ -541,7 +542,7 @@ to mail.outbox:: | ||||
|     # Empty the test outbox | ||||
|     mail.outbox = [] | ||||
|  | ||||
| .. _`Django email services`: ../email/ | ||||
| .. _`Django e-mail services`: ../email/ | ||||
| .. _`SMTPConnection`: ../email/#the-emailmessage-and-smtpconnection-classes | ||||
| .. _`EmailMessage`: ../email/#the-emailmessage-and-smtpconnection-classes | ||||
| .. _`previously`: #emptying-the-test-outbox | ||||
| @@ -669,7 +670,7 @@ a number of utility methods in the ``django.test.utils`` module. | ||||
|  | ||||
| ``teardown_test_environment()`` | ||||
|     Performs any global post-test teardown, such as removing the instrumentation | ||||
|     of the template rendering system and restoring normal email services. | ||||
|     of the template rendering system and restoring normal e-mail services. | ||||
|  | ||||
| ``create_test_db(verbosity=1, autoclobber=False)`` | ||||
|     Creates a new test database, and run ``syncdb`` against it. | ||||
|   | ||||
| @@ -179,6 +179,18 @@ fields with the 'choices' attribute are represented by a ChoiceField. | ||||
| <option value="3">Third test</option> | ||||
| </select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr> | ||||
|  | ||||
| You can restrict a form to a subset of the complete list of fields | ||||
| by providing a 'fields' argument. If you try to save a | ||||
| model created with such a form, you need to ensure that the fields | ||||
| that are _not_ on the form have default values, or are allowed to have | ||||
| a value of None. If a field isn't specified on a form, the object created | ||||
| from the form can't provide a value for that field! | ||||
| >>> PartialArticleForm = form_for_model(Article, fields=('headline','pub_date')) | ||||
| >>> f = PartialArticleForm(auto_id=False) | ||||
| >>> print f | ||||
| <tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr> | ||||
| <tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr> | ||||
|  | ||||
| You can pass a custom Form class to form_for_model. Make sure it's a | ||||
| subclass of BaseForm, not Form. | ||||
| >>> class CustomForm(BaseForm): | ||||
| @@ -224,7 +236,23 @@ current values are inserted as 'initial' data in each Field. | ||||
| <option value="2">It's a test</option> | ||||
| <option value="3">Third test</option> | ||||
| </select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li> | ||||
| >>> f = TestArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04', 'writer': u'1', 'article': 'Hello.'}) | ||||
| >>> f = TestArticleForm({'headline': u'Test headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'}) | ||||
| >>> f.is_valid() | ||||
| True | ||||
| >>> test_art = f.save() | ||||
| >>> test_art.id | ||||
| 1 | ||||
| >>> test_art = Article.objects.get(id=1) | ||||
| >>> test_art.headline | ||||
| 'Test headline' | ||||
|  | ||||
| You can create a form over a subset of the available fields  | ||||
| by specifying a 'fields' argument to form_for_instance.  | ||||
| >>> PartialArticleForm = form_for_instance(art, fields=('headline','pub_date')) | ||||
| >>> f = PartialArticleForm({'headline': u'New headline', 'pub_date': u'1988-01-04'}, auto_id=False) | ||||
| >>> print f.as_ul() | ||||
| <li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li> | ||||
| <li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li> | ||||
| >>> f.is_valid() | ||||
| True | ||||
| >>> new_art = f.save() | ||||
|   | ||||
| @@ -34,4 +34,18 @@ Unicode decoding problems... | ||||
| >>> f = SomeForm() | ||||
| >>> f.as_p() | ||||
| u'<p><label for="id_somechoice_0">Somechoice:</label> <ul>\n<li><label><input type="radio" id="id_somechoice_0" value="0" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="1" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="2" name="somechoice" /> Nainen</label></li>\n</ul></p>' | ||||
|  | ||||
| ####################### | ||||
| # Miscellaneous Tests # | ||||
| ####################### | ||||
|  | ||||
| There once was a problem with Form fields called "data". Let's make sure that | ||||
| doesn't come back. | ||||
| >>> class DataForm(Form): | ||||
| ...     data = CharField(max_length=10) | ||||
| >>> f = DataForm({'data': 'xyzzy'}) | ||||
| >>> f.is_valid() | ||||
| True | ||||
| >>> f.clean_data | ||||
| {'data': u'xyzzy'} | ||||
| """ | ||||
|   | ||||
| @@ -1916,6 +1916,34 @@ True | ||||
| >>> p.clean_data | ||||
| {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} | ||||
|  | ||||
| clean_data will include a key and value for *all* fields defined in the Form, | ||||
| even if the Form's data didn't include a value for fields that are not | ||||
| required. In this example, the data dictionary doesn't include a value for the | ||||
| "nick_name" field, but clean_data includes it. For CharFields, it's set to the | ||||
| empty string. | ||||
| >>> class OptionalPersonForm(Form): | ||||
| ...     first_name = CharField() | ||||
| ...     last_name = CharField() | ||||
| ...     nick_name = CharField(required=False) | ||||
| >>> data = {'first_name': u'John', 'last_name': u'Lennon'} | ||||
| >>> f = OptionalPersonForm(data) | ||||
| >>> f.is_valid() | ||||
| True | ||||
| >>> f.clean_data | ||||
| {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} | ||||
|  | ||||
| For DateFields, it's set to None. | ||||
| >>> class OptionalPersonForm(Form): | ||||
| ...     first_name = CharField() | ||||
| ...     last_name = CharField() | ||||
| ...     birth_date = DateField(required=False) | ||||
| >>> data = {'first_name': u'John', 'last_name': u'Lennon'} | ||||
| >>> f = OptionalPersonForm(data) | ||||
| >>> f.is_valid() | ||||
| True | ||||
| >>> f.clean_data | ||||
| {'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'} | ||||
|  | ||||
| "auto_id" tells the Form to add an "id" attribute to each form element. | ||||
| If it's a string that contains '%s', Django will use that as a format string | ||||
| into which the field's name will be inserted. It will also put a <label> around | ||||
| @@ -2275,7 +2303,7 @@ returns a list of input. | ||||
| Validation errors are HTML-escaped when output as HTML. | ||||
| >>> class EscapingForm(Form): | ||||
| ...     special_name = CharField() | ||||
| ...     def clean_special_name(self): | ||||
| ...     def do_clean_special_name(self): | ||||
| ...         raise ValidationError("Something's wrong with '%s'" % self.clean_data['special_name']) | ||||
|  | ||||
| >>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False) | ||||
| @@ -2298,7 +2326,7 @@ including the current field (e.g., the field XXX if you're in clean_XXX()). | ||||
| ...    username = CharField(max_length=10) | ||||
| ...    password1 = CharField(widget=PasswordInput) | ||||
| ...    password2 = CharField(widget=PasswordInput) | ||||
| ...    def clean_password2(self): | ||||
| ...    def do_clean_password2(self): | ||||
| ...        if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: | ||||
| ...            raise ValidationError(u'Please make sure your passwords match.') | ||||
| ...        return self.clean_data['password2'] | ||||
| @@ -2752,6 +2780,64 @@ then the latter will get precedence. | ||||
| <li>Username: <input type="text" name="username" value="babik" maxlength="10" /></li> | ||||
| <li>Password: <input type="password" name="password" /></li> | ||||
|  | ||||
| # Callable initial data ######################################################## | ||||
|  | ||||
| The previous technique dealt with raw values as initial data, but it's also | ||||
| possible to specify callable data. | ||||
|  | ||||
| >>> class UserRegistration(Form): | ||||
| ...    username = CharField(max_length=10) | ||||
| ...    password = CharField(widget=PasswordInput) | ||||
|  | ||||
| We need to define functions that get called later. | ||||
| >>> def initial_django(): | ||||
| ...     return 'django' | ||||
| >>> def initial_stephane(): | ||||
| ...     return 'stephane' | ||||
|  | ||||
| Here, we're not submitting any data, so the initial value will be displayed. | ||||
| >>> p = UserRegistration(initial={'username': initial_django}, auto_id=False) | ||||
| >>> print p.as_ul() | ||||
| <li>Username: <input type="text" name="username" value="django" maxlength="10" /></li> | ||||
| <li>Password: <input type="password" name="password" /></li> | ||||
|  | ||||
| The 'initial' parameter is meaningless if you pass data. | ||||
| >>> p = UserRegistration({}, initial={'username': initial_django}, auto_id=False) | ||||
| >>> print p.as_ul() | ||||
| <li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li> | ||||
| <li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li> | ||||
| >>> p = UserRegistration({'username': u''}, initial={'username': initial_django}, auto_id=False) | ||||
| >>> print p.as_ul() | ||||
| <li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li> | ||||
| <li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li> | ||||
| >>> p = UserRegistration({'username': u'foo'}, initial={'username': initial_django}, auto_id=False) | ||||
| >>> print p.as_ul() | ||||
| <li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li> | ||||
| <li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li> | ||||
|  | ||||
| A callable 'initial' value is *not* used as a fallback if data is not provided. | ||||
| In this example, we don't provide a value for 'username', and the form raises a | ||||
| validation error rather than using the initial value for 'username'. | ||||
| >>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django}) | ||||
| >>> p.errors | ||||
| {'username': [u'This field is required.']} | ||||
| >>> p.is_valid() | ||||
| False | ||||
|  | ||||
| If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(), | ||||
| then the latter will get precedence. | ||||
| >>> class UserRegistration(Form): | ||||
| ...    username = CharField(max_length=10, initial=initial_django) | ||||
| ...    password = CharField(widget=PasswordInput) | ||||
| >>> p = UserRegistration(auto_id=False) | ||||
| >>> print p.as_ul() | ||||
| <li>Username: <input type="text" name="username" value="django" maxlength="10" /></li> | ||||
| <li>Password: <input type="password" name="password" /></li> | ||||
| >>> p = UserRegistration(initial={'username': initial_stephane}, auto_id=False) | ||||
| >>> print p.as_ul() | ||||
| <li>Username: <input type="text" name="username" value="stephane" maxlength="10" /></li> | ||||
| <li>Password: <input type="password" name="password" /></li> | ||||
|  | ||||
| # Help text ################################################################### | ||||
|  | ||||
| You can specify descriptive text for a field by using the 'help_text' argument | ||||
| @@ -3320,7 +3406,7 @@ True | ||||
| </select> | ||||
|  | ||||
| # MultiWidget and MultiValueField ############################################# | ||||
| # MultiWidgets are widgets composed of other widgets. They are usually  | ||||
| # MultiWidgets are widgets composed of other widgets. They are usually | ||||
| # combined with MultiValueFields - a field that is composed of other fields. | ||||
| # MulitWidgets can themselved be composed of other MultiWidgets. | ||||
| # SplitDateTimeWidget is one example of a MultiWidget. | ||||
| @@ -3328,7 +3414,7 @@ True | ||||
| >>> class ComplexMultiWidget(MultiWidget): | ||||
| ...     def __init__(self, attrs=None): | ||||
| ...         widgets = ( | ||||
| ...             TextInput(),  | ||||
| ...             TextInput(), | ||||
| ...             SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), | ||||
| ...             SplitDateTimeWidget(), | ||||
| ...         ) | ||||
| @@ -3353,13 +3439,13 @@ True | ||||
| <input type="text" name="name_2_0" value="2007-04-25" /><input type="text" name="name_2_1" value="06:24:00" /> | ||||
|  | ||||
| >>> class ComplexField(MultiValueField): | ||||
| ...     def __init__(self, required=True, widget=None, label=None, initial=None):  | ||||
| ...     def __init__(self, required=True, widget=None, label=None, initial=None): | ||||
| ...         fields = ( | ||||
| ...             CharField(),  | ||||
| ...             CharField(), | ||||
| ...             MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), | ||||
| ...             SplitDateTimeField() | ||||
| ...         ) | ||||
| ...         super(ComplexField, self).__init__(fields, required, widget, label, initial)  | ||||
| ...         super(ComplexField, self).__init__(fields, required, widget, label, initial) | ||||
| ... | ||||
| ...     def compress(self, data_list): | ||||
| ...         if data_list: | ||||
|   | ||||
| @@ -100,6 +100,12 @@ class Anchor(models.Model): | ||||
|     something for other models to point at""" | ||||
|      | ||||
|     data = models.CharField(maxlength=30) | ||||
|  | ||||
| class UniqueAnchor(models.Model): | ||||
|     """This is a model that can be used as  | ||||
|     something for other models to point at""" | ||||
|  | ||||
|     data = models.CharField(unique=True, maxlength=30) | ||||
|      | ||||
| class FKData(models.Model): | ||||
|     data = models.ForeignKey(Anchor, null=True) | ||||
| @@ -116,6 +122,10 @@ class FKSelfData(models.Model): | ||||
| class M2MSelfData(models.Model): | ||||
|     data = models.ManyToManyField('self', null=True, symmetrical=False) | ||||
|  | ||||
|  | ||||
| class FKDataToField(models.Model): | ||||
|     data = models.ForeignKey(UniqueAnchor, null=True, to_field='data') | ||||
|  | ||||
| # The following test classes are for validating the | ||||
| # deserialization of objects that use a user-defined | ||||
| # field as the primary key. | ||||
|   | ||||
| @@ -159,6 +159,7 @@ The end."""), | ||||
|  | ||||
|     (data_obj, 300, Anchor, "Anchor 1"), | ||||
|     (data_obj, 301, Anchor, "Anchor 2"), | ||||
|     (data_obj, 302, UniqueAnchor, "UAnchor 1"), | ||||
|  | ||||
|     (fk_obj, 400, FKData, 300), # Post reference | ||||
|     (fk_obj, 401, FKData, 500), # Pre reference | ||||
| @@ -184,8 +185,13 @@ The end."""), | ||||
|     (m2m_obj, 445, M2MSelfData, []), | ||||
|     (m2m_obj, 446, M2MSelfData, []), | ||||
|  | ||||
|     (fk_obj, 450, FKDataToField, "UAnchor 1"), | ||||
|     (fk_obj, 451, FKDataToField, "UAnchor 2"), | ||||
|     (fk_obj, 452, FKDataToField, None), | ||||
|      | ||||
|     (data_obj, 500, Anchor, "Anchor 3"), | ||||
|     (data_obj, 501, Anchor, "Anchor 4"), | ||||
|     (data_obj, 502, UniqueAnchor, "UAnchor 2"), | ||||
|  | ||||
|     (pk_obj, 601, BooleanPKData, True), | ||||
|     (pk_obj, 602, BooleanPKData, False), | ||||
|   | ||||
| @@ -60,7 +60,35 @@ class AssertTemplateUsedTests(TestCase): | ||||
|             self.assertTemplateUsed(response, "Valid POST Template")         | ||||
|         except AssertionError, e: | ||||
|             self.assertEquals(str(e), "Template 'Valid POST Template' was not one of the templates used to render the response. Templates used: ['form_view.html', 'base.html']") | ||||
|  | ||||
| class AssertRedirectsTests(TestCase): | ||||
|     def test_redirect_page(self): | ||||
|         "An assertion is raised if the original page couldn't be retrieved as expected"         | ||||
|         # This page will redirect with code 301, not 302 | ||||
|         response = self.client.get('/test_client/permanent_redirect_view/')         | ||||
|         try: | ||||
|             self.assertRedirects(response, '/test_client/get_view/') | ||||
|         except AssertionError, e: | ||||
|             self.assertEquals(str(e), "Response didn't redirect as expected: Reponse code was 301 (expected 302)") | ||||
|  | ||||
|     def test_incorrect_target(self): | ||||
|         "An assertion is raised if the response redirects to another target" | ||||
|         response = self.client.get('/test_client/permanent_redirect_view/')         | ||||
|         try: | ||||
|             # Should redirect to get_view | ||||
|             self.assertRedirects(response, '/test_client/some_view/') | ||||
|         except AssertionError, e: | ||||
|             self.assertEquals(str(e), "Response didn't redirect as expected: Reponse code was 301 (expected 302)") | ||||
|          | ||||
|     def test_target_page(self): | ||||
|         "An assertion is raised if the reponse redirect target cannot be retrieved as expected" | ||||
|         response = self.client.get('/test_client/double_redirect_view/') | ||||
|         try: | ||||
|             # The redirect target responds with a 301 code, not 200 | ||||
|             self.assertRedirects(response, '/test_client/permanent_redirect_view/') | ||||
|         except AssertionError, e: | ||||
|             self.assertEquals(str(e), "Couldn't retrieve redirection page '/test_client/permanent_redirect_view/': response code was 301 (expected 200)") | ||||
|              | ||||
| class AssertFormErrorTests(TestCase): | ||||
|     def test_unknown_form(self): | ||||
|         "An assertion is raised if the form name is unknown" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user