Django forms, inheritance and order of form fields


Question

I'm using Django forms in my website and would like to control the order of the fields.

Here's how I define my forms:

class edit_form(forms.Form):
    summary = forms.CharField()
    description = forms.CharField(widget=forms.TextArea)


class create_form(edit_form):
    name = forms.CharField()

The name is immutable and should only be listed when the entity is created. I use inheritance to add consistency and DRY principles. What happens which is not erroneous, in fact totally expected, is that the name field is listed last in the view/html but I'd like the name field to be on top of summary and description. I do realize that I could easily fix it by copying summary and description into create_form and loose the inheritance but I'd like to know if this is possible.

Why? Imagine you've got 100 fields in edit_form and have to add 10 fields on the top in create_form - copying and maintaining the two forms wouldn't look so sexy then. (This is not my case, I'm just making up an example)

So, how can I override this behavior?

Edit:

Apparently there's no proper way to do this without going through nasty hacks (fiddling with .field attribute). The .field attribute is a SortedDict (one of Django's internal datastructures) which doesn't provide any way to reorder key:value pairs. It does how-ever provide a way to insert items at a given index but that would move the items from the class members and into the constructor. This method would work, but make the code less readable. The only other way I see fit is to modify the framework itself which is less-than-optimal in most situations.

In short the code would become something like this:

class edit_form(forms.Form):
    summary = forms.CharField()
    description = forms.CharField(widget=forms.TextArea)


class create_form(edit_form):
    def __init__(self,*args,**kwargs):
        forms.Form.__init__(self,*args,**kwargs)

        self.fields.insert(0,'name',forms.CharField())

That shut me up :)

1
62
5/27/2009 6:39:34 PM

Accepted Answer

From Django 1.9+

Django 1.9 adds a new Form attribute, field_order, allowing to order the field regardless their order of declaration in the class.

class MyForm(forms.Form):
    summary = forms.CharField()
    description = forms.CharField(widget=forms.TextArea)
    author = forms.CharField()
    notes = form.CharField()

    field_order = ['author', 'summary']

Missing fields in field_order keep their order in the class and are appended after the ones specified in the list. The example above will produce the fields in this order: ['author', 'summary', 'description', 'notes']

See the documentation: https://docs.djangoproject.com/en/stable/ref/forms/api/#notes-on-field-ordering

Up to Django 1.6

I had this same problem and I found another technique for reordering fields in the Django CookBook:

class EditForm(forms.Form):
    summary = forms.CharField()
    description = forms.CharField(widget=forms.TextArea)


class CreateForm(EditForm):
    name = forms.CharField()

    def __init__(self, *args, **kwargs):
        super(CreateForm, self).__init__(*args, **kwargs)
        self.fields.keyOrder = ['name', 'summary', 'description']
99
4/25/2018 8:08:27 AM

From Django 1.9: https://docs.djangoproject.com/en/1.10/ref/forms/api/#notes-on-field-ordering


Original answer: Django 1.9 will support this by default on the form with field_order:

class MyForm(forms.Form):
    ...
    field_order = ['field_1', 'field_2']
    ...

https://github.com/django/django/commit/28986da4ca167ae257abcaf7caea230eca2bcd80


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon