If I have a Django form such as:
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = fo
With Django >= 1.7 your must modify ContactForm.base_fields
as below:
from collections import OrderedDict
...
class ContactForm(forms.Form):
...
ContactForm.base_fields = OrderedDict(
(k, ContactForm.base_fields[k])
for k in ['your', 'field', 'in', 'order']
)
This trick is used in Django Admin PasswordChangeForm
: Source on Github
It has to do with the meta class that is used in defining the form class. I think it keeps an internal list of the fields and if you insert into the middle of the list it might work. It has been a while since I looked at that code.
I've used this to move fields about:
def move_field_before(frm, field_name, before_name):
fld = frm.fields.pop(field_name)
pos = frm.fields.keys().index(before_name)
frm.fields.insert(pos, field_name, fld)
This works in 1.5 and I'm reasonably sure it still works in more recent versions.
New to Django 1.9 is Form.field_order and Form.order_fields().
# forms.Form example
class SignupForm(forms.Form):
password = ...
email = ...
username = ...
field_order = ['username', 'email', 'password']
# forms.ModelForm example
class UserAccount(forms.ModelForm):
custom_field = models.CharField(max_length=254)
def Meta:
model = User
fields = ('username', 'email')
field_order = ['username', 'custom_field', 'password']
Using fields
in inner Meta
class is what worked for me on Django==1.6.5
:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Example form declaration with custom field order.
"""
from django import forms
from app.models import AppModel
class ExampleModelForm(forms.ModelForm):
"""
An example model form for ``AppModel``.
"""
field1 = forms.CharField()
field2 = forms.CharField()
class Meta:
model = AppModel
fields = ['field2', 'field1']
As simple as that.
Form fields have an attribute for creation order, called creation_counter
. .fields
attribute is a dictionary, so simple adding to dictionary and changing creation_counter
attributes in all fields to reflect new ordering should suffice (never tried this, though).