mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #32920 -- Changed BaseForm to access its values through bound fields.
This commit is contained in:
		
				
					committed by
					
						 Carlton Gibson
						Carlton Gibson
					
				
			
			
				
	
			
			
			
						parent
						
							84400d2e9d
						
					
				
				
					commit
					90a33ab2ce
				
			| @@ -143,7 +143,13 @@ class BaseForm: | ||||
|             'fields': ';'.join(self.fields), | ||||
|         } | ||||
|  | ||||
|     def _bound_items(self): | ||||
|         """Yield (name, bf) pairs, where bf is a BoundField object.""" | ||||
|         for name in self.fields: | ||||
|             yield name, self[name] | ||||
|  | ||||
|     def __iter__(self): | ||||
|         """Yield the form's fields as BoundField objects.""" | ||||
|         for name in self.fields: | ||||
|             yield self[name] | ||||
|  | ||||
| @@ -206,9 +212,9 @@ class BaseForm: | ||||
|         top_errors = self.non_field_errors().copy() | ||||
|         output, hidden_fields = [], [] | ||||
|  | ||||
|         for name, field in self.fields.items(): | ||||
|         for name, bf in self._bound_items(): | ||||
|             field = bf.field | ||||
|             html_class_attr = '' | ||||
|             bf = self[name] | ||||
|             bf_errors = self.error_class(bf.errors) | ||||
|             if bf.is_hidden: | ||||
|                 if bf_errors: | ||||
| @@ -387,15 +393,12 @@ class BaseForm: | ||||
|         self._post_clean() | ||||
|  | ||||
|     def _clean_fields(self): | ||||
|         for name, field in self.fields.items(): | ||||
|             if field.disabled: | ||||
|                 value = self.get_initial_for_field(field, name) | ||||
|             else: | ||||
|                 value = self._field_data_value(field, self.add_prefix(name)) | ||||
|         for name, bf in self._bound_items(): | ||||
|             field = bf.field | ||||
|             value = bf.initial if field.disabled else bf.data | ||||
|             try: | ||||
|                 if isinstance(field, FileField): | ||||
|                     initial = self.get_initial_for_field(field, name) | ||||
|                     value = field.clean(value, initial) | ||||
|                     value = field.clean(value, bf.initial) | ||||
|                 else: | ||||
|                     value = field.clean(value) | ||||
|                 self.cleaned_data[name] = value | ||||
| @@ -437,24 +440,23 @@ class BaseForm: | ||||
|     @cached_property | ||||
|     def changed_data(self): | ||||
|         data = [] | ||||
|         for name, field in self.fields.items(): | ||||
|             data_value = self._field_data_value(field, self.add_prefix(name)) | ||||
|         for name, bf in self._bound_items(): | ||||
|             field = bf.field | ||||
|             if not field.show_hidden_initial: | ||||
|                 # Use the BoundField's initial as this is the value passed to | ||||
|                 # the widget. | ||||
|                 initial_value = self[name].initial | ||||
|                 initial_value = bf.initial | ||||
|             else: | ||||
|                 initial_prefixed_name = self.add_initial_prefix(name) | ||||
|                 hidden_widget = field.hidden_widget() | ||||
|                 try: | ||||
|                     initial_value = field.to_python( | ||||
|                         self._widget_data_value(hidden_widget, initial_prefixed_name) | ||||
|                         self._widget_data_value(hidden_widget, bf.html_initial_name) | ||||
|                     ) | ||||
|                 except ValidationError: | ||||
|                     # Always assume data has changed if validation fails. | ||||
|                     data.append(name) | ||||
|                     continue | ||||
|             if field.has_changed(initial_value, data_value): | ||||
|             if field.has_changed(initial_value, bf.data): | ||||
|                 data.append(name) | ||||
|         return data | ||||
|  | ||||
|   | ||||
| @@ -2112,15 +2112,47 @@ Password: <input type="password" name="password" required></li> | ||||
|         self.assertEqual(unbound['hi_without_microsec'].value(), now_no_ms) | ||||
|         self.assertEqual(unbound['ti_without_microsec'].value(), now_no_ms) | ||||
|  | ||||
|     def test_datetime_clean_initial_callable_disabled(self): | ||||
|         now = datetime.datetime(2006, 10, 25, 14, 30, 45, 123456) | ||||
|     def get_datetime_form_with_callable_initial(self, disabled, microseconds=0): | ||||
|         class FakeTime: | ||||
|             def __init__(self): | ||||
|                 self.elapsed_seconds = 0 | ||||
|  | ||||
|             def now(self): | ||||
|                 self.elapsed_seconds += 1 | ||||
|                 return datetime.datetime( | ||||
|                     2006, 10, 25, 14, 30, 45 + self.elapsed_seconds, | ||||
|                     microseconds, | ||||
|                 ) | ||||
|  | ||||
|         class DateTimeForm(forms.Form): | ||||
|             dt = DateTimeField(initial=lambda: now, disabled=True) | ||||
|             dt = DateTimeField(initial=FakeTime().now, disabled=disabled) | ||||
|  | ||||
|         form = DateTimeForm({}) | ||||
|         return DateTimeForm({}) | ||||
|  | ||||
|     def test_datetime_clean_disabled_callable_initial_microseconds(self): | ||||
|         """ | ||||
|         Cleaning a form with a disabled DateTimeField and callable initial | ||||
|         removes microseconds. | ||||
|         """ | ||||
|         form = self.get_datetime_form_with_callable_initial( | ||||
|             disabled=True, microseconds=123456, | ||||
|         ) | ||||
|         self.assertEqual(form.errors, {}) | ||||
|         self.assertEqual(form.cleaned_data, {'dt': now}) | ||||
|         self.assertEqual(form.cleaned_data, { | ||||
|             'dt': datetime.datetime(2006, 10, 25, 14, 30, 46), | ||||
|         }) | ||||
|  | ||||
|     def test_datetime_clean_disabled_callable_initial_bound_field(self): | ||||
|         """ | ||||
|         The cleaned value for a form with a disabled DateTimeField and callable | ||||
|         initial matches the bound field's cached initial value. | ||||
|         """ | ||||
|         form = self.get_datetime_form_with_callable_initial(disabled=True) | ||||
|         self.assertEqual(form.errors, {}) | ||||
|         cleaned = form.cleaned_data['dt'] | ||||
|         self.assertEqual(cleaned, datetime.datetime(2006, 10, 25, 14, 30, 46)) | ||||
|         bf = form['dt'] | ||||
|         self.assertEqual(cleaned, bf.initial) | ||||
|  | ||||
|     def test_datetime_changed_data_callable_with_microseconds(self): | ||||
|         class DateTimeForm(forms.Form): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user