Loading django/contrib/auth/forms.py +2 −7 Original line number Diff line number Diff line from __future__ import unicode_literals from collections import OrderedDict from django import forms from django.contrib.auth import authenticate, get_user_model from django.contrib.auth.hashers import ( Loading Loading @@ -303,6 +301,8 @@ class PasswordChangeForm(SetPasswordForm): old_password = forms.CharField(label=_("Old password"), widget=forms.PasswordInput) field_order = ['old_password', 'new_password1', 'new_password2'] def clean_old_password(self): """ Validates that the old_password field is correct. Loading @@ -315,11 +315,6 @@ class PasswordChangeForm(SetPasswordForm): ) return old_password PasswordChangeForm.base_fields = OrderedDict( (k, PasswordChangeForm.base_fields[k]) for k in ['old_password', 'new_password1', 'new_password2'] ) class AdminPasswordChangeForm(forms.Form): """ Loading django/forms/forms.py +26 −1 Original line number Diff line number Diff line Loading @@ -73,9 +73,11 @@ class BaseForm(object): # class is different than Form. See the comments by the Form class for more # information. Any improvements to the form API should be made to *this* # class, not to the Form class. field_order = None def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=ErrorList, label_suffix=None, empty_permitted=False): empty_permitted=False, field_order=None): self.is_bound = data is not None or files is not None self.data = data or {} self.files = files or {} Loading @@ -96,6 +98,29 @@ class BaseForm(object): # self.base_fields. self.fields = copy.deepcopy(self.base_fields) self._bound_fields_cache = {} self.order_fields(self.field_order if field_order is None else field_order) def order_fields(self, field_order): """ Rearranges the fields according to field_order. field_order is a list of field names specifying the order. Fields not included in the list are appended in the default order for backward compatibility with subclasses not overriding field_order. If field_order is None, all fields are kept in the order defined in the class. Unknown fields in field_order are ignored to allow disabling fields in form subclasses without redefining ordering. """ if field_order is None: return fields = OrderedDict() for key in field_order: try: fields[key] = self.fields.pop(key) except KeyError: # ignore unknown fields pass fields.update(self.fields) # add remaining fields in original order self.fields = fields def __str__(self): return self.as_table() Loading docs/ref/forms/api.txt +25 −0 Original line number Diff line number Diff line Loading @@ -700,6 +700,31 @@ example, in the ``ContactForm`` example, the fields are defined in the order ``subject``, ``message``, ``sender``, ``cc_myself``. To reorder the HTML output, just change the order in which those fields are listed in the class. There are several other ways to customize the order: .. attribute:: Form.field_order .. versionadded:: 1.9 By default ``Form.field_order=None``, which retains the order in which you define the fields in your form class. If ``field_order`` is a list of field names, the fields are ordered as specified by the list and remaining fields are appended according to the default order. Unknown field names in the list are ignored. This makes it possible to disable a field in a subclass by setting it to ``None`` without having to redefine ordering. You can also use the ``Form.field_order`` argument to a :class:`Form` to override the field order. If a :class:`~django.forms.Form` defines :attr:`~Form.field_order` *and* you include ``field_order`` when instantiating the ``Form``, then the latter ``field_order`` will have precedence. .. method:: Form.order_fields(field_order) .. versionadded:: 1.9 You may rearrange the fields any time using ``order_fields()`` with a list of field names as in :attr:`~django.forms.Form.field_order`. How errors are displayed ~~~~~~~~~~~~~~~~~~~~~~~~ Loading docs/releases/1.9.txt +4 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ Forms ``field_classes`` to customize the type of the fields. See :ref:`modelforms-overriding-default-fields` for details. * You can now specify the order in which form fields are rendered with the :attr:`~django.forms.Form.field_order` attribute, the ``field_order`` constructor argument , or the :meth:`~django.forms.Form.order_fields` method. Generic Views ^^^^^^^^^^^^^ Loading tests/forms_tests/tests/test_forms.py +43 −0 Original line number Diff line number Diff line Loading @@ -1046,6 +1046,49 @@ class FormsTestCase(TestCase): <tr><th>Field13:</th><td><input type="text" name="field13" /></td></tr> <tr><th>Field14:</th><td><input type="text" name="field14" /></td></tr>""") def test_explicit_field_order(self): class TestFormParent(Form): field1 = CharField() field2 = CharField() field4 = CharField() field5 = CharField() field6 = CharField() field_order = ['field6', 'field5', 'field4', 'field2', 'field1'] class TestForm(TestFormParent): field3 = CharField() field_order = ['field2', 'field4', 'field3', 'field5', 'field6'] class TestFormRemove(TestForm): field1 = None class TestFormMissing(TestForm): field_order = ['field2', 'field4', 'field3', 'field5', 'field6', 'field1'] field1 = None class TestFormInit(TestFormParent): field3 = CharField() field_order = None def __init__(self, **kwargs): super(TestFormInit, self).__init__(**kwargs) self.order_fields(field_order=TestForm.field_order) p = TestFormParent() self.assertEqual(list(p.fields.keys()), TestFormParent.field_order) p = TestFormRemove() self.assertEqual(list(p.fields.keys()), TestForm.field_order) p = TestFormMissing() self.assertEqual(list(p.fields.keys()), TestForm.field_order) p = TestForm() self.assertEqual(list(p.fields.keys()), TestFormMissing.field_order) p = TestFormInit() order = list(TestForm.field_order) + ['field1'] self.assertEqual(list(p.fields.keys()), order) TestForm.field_order = ['unknown'] p = TestForm() self.assertEqual(list(p.fields.keys()), ['field1', 'field2', 'field4', 'field5', 'field6', 'field3']) def test_form_html_attributes(self): # Some Field classes have an effect on the HTML attributes of their associated # Widget. If you set max_length in a CharField and its associated widget is Loading Loading
django/contrib/auth/forms.py +2 −7 Original line number Diff line number Diff line from __future__ import unicode_literals from collections import OrderedDict from django import forms from django.contrib.auth import authenticate, get_user_model from django.contrib.auth.hashers import ( Loading Loading @@ -303,6 +301,8 @@ class PasswordChangeForm(SetPasswordForm): old_password = forms.CharField(label=_("Old password"), widget=forms.PasswordInput) field_order = ['old_password', 'new_password1', 'new_password2'] def clean_old_password(self): """ Validates that the old_password field is correct. Loading @@ -315,11 +315,6 @@ class PasswordChangeForm(SetPasswordForm): ) return old_password PasswordChangeForm.base_fields = OrderedDict( (k, PasswordChangeForm.base_fields[k]) for k in ['old_password', 'new_password1', 'new_password2'] ) class AdminPasswordChangeForm(forms.Form): """ Loading
django/forms/forms.py +26 −1 Original line number Diff line number Diff line Loading @@ -73,9 +73,11 @@ class BaseForm(object): # class is different than Form. See the comments by the Form class for more # information. Any improvements to the form API should be made to *this* # class, not to the Form class. field_order = None def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=ErrorList, label_suffix=None, empty_permitted=False): empty_permitted=False, field_order=None): self.is_bound = data is not None or files is not None self.data = data or {} self.files = files or {} Loading @@ -96,6 +98,29 @@ class BaseForm(object): # self.base_fields. self.fields = copy.deepcopy(self.base_fields) self._bound_fields_cache = {} self.order_fields(self.field_order if field_order is None else field_order) def order_fields(self, field_order): """ Rearranges the fields according to field_order. field_order is a list of field names specifying the order. Fields not included in the list are appended in the default order for backward compatibility with subclasses not overriding field_order. If field_order is None, all fields are kept in the order defined in the class. Unknown fields in field_order are ignored to allow disabling fields in form subclasses without redefining ordering. """ if field_order is None: return fields = OrderedDict() for key in field_order: try: fields[key] = self.fields.pop(key) except KeyError: # ignore unknown fields pass fields.update(self.fields) # add remaining fields in original order self.fields = fields def __str__(self): return self.as_table() Loading
docs/ref/forms/api.txt +25 −0 Original line number Diff line number Diff line Loading @@ -700,6 +700,31 @@ example, in the ``ContactForm`` example, the fields are defined in the order ``subject``, ``message``, ``sender``, ``cc_myself``. To reorder the HTML output, just change the order in which those fields are listed in the class. There are several other ways to customize the order: .. attribute:: Form.field_order .. versionadded:: 1.9 By default ``Form.field_order=None``, which retains the order in which you define the fields in your form class. If ``field_order`` is a list of field names, the fields are ordered as specified by the list and remaining fields are appended according to the default order. Unknown field names in the list are ignored. This makes it possible to disable a field in a subclass by setting it to ``None`` without having to redefine ordering. You can also use the ``Form.field_order`` argument to a :class:`Form` to override the field order. If a :class:`~django.forms.Form` defines :attr:`~Form.field_order` *and* you include ``field_order`` when instantiating the ``Form``, then the latter ``field_order`` will have precedence. .. method:: Form.order_fields(field_order) .. versionadded:: 1.9 You may rearrange the fields any time using ``order_fields()`` with a list of field names as in :attr:`~django.forms.Form.field_order`. How errors are displayed ~~~~~~~~~~~~~~~~~~~~~~~~ Loading
docs/releases/1.9.txt +4 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ Forms ``field_classes`` to customize the type of the fields. See :ref:`modelforms-overriding-default-fields` for details. * You can now specify the order in which form fields are rendered with the :attr:`~django.forms.Form.field_order` attribute, the ``field_order`` constructor argument , or the :meth:`~django.forms.Form.order_fields` method. Generic Views ^^^^^^^^^^^^^ Loading
tests/forms_tests/tests/test_forms.py +43 −0 Original line number Diff line number Diff line Loading @@ -1046,6 +1046,49 @@ class FormsTestCase(TestCase): <tr><th>Field13:</th><td><input type="text" name="field13" /></td></tr> <tr><th>Field14:</th><td><input type="text" name="field14" /></td></tr>""") def test_explicit_field_order(self): class TestFormParent(Form): field1 = CharField() field2 = CharField() field4 = CharField() field5 = CharField() field6 = CharField() field_order = ['field6', 'field5', 'field4', 'field2', 'field1'] class TestForm(TestFormParent): field3 = CharField() field_order = ['field2', 'field4', 'field3', 'field5', 'field6'] class TestFormRemove(TestForm): field1 = None class TestFormMissing(TestForm): field_order = ['field2', 'field4', 'field3', 'field5', 'field6', 'field1'] field1 = None class TestFormInit(TestFormParent): field3 = CharField() field_order = None def __init__(self, **kwargs): super(TestFormInit, self).__init__(**kwargs) self.order_fields(field_order=TestForm.field_order) p = TestFormParent() self.assertEqual(list(p.fields.keys()), TestFormParent.field_order) p = TestFormRemove() self.assertEqual(list(p.fields.keys()), TestForm.field_order) p = TestFormMissing() self.assertEqual(list(p.fields.keys()), TestForm.field_order) p = TestForm() self.assertEqual(list(p.fields.keys()), TestFormMissing.field_order) p = TestFormInit() order = list(TestForm.field_order) + ['field1'] self.assertEqual(list(p.fields.keys()), order) TestForm.field_order = ['unknown'] p = TestForm() self.assertEqual(list(p.fields.keys()), ['field1', 'field2', 'field4', 'field5', 'field6', 'field3']) def test_form_html_attributes(self): # Some Field classes have an effect on the HTML attributes of their associated # Widget. If you set max_length in a CharField and its associated widget is Loading