Changes between Initial Version and Version 1 of CookBookNewFormsFieldOrdering

12/28/2007 09:39:38 PM (12 years ago)
Todd O'Bryan



  • CookBookNewFormsFieldOrdering

    v1 v1  
     1= Field Ordering in newforms =
     3As you know, displaying a form using `as_table()`, `as_p()`, or `as_ul()` displays the form's fields in whatever order they're listed in the the form class. This is usually fine, because the order in the class is completely flexible. There are some cases, however, when it can get annoying.
     5Imagine you run a bookstore and are creating forms for people to enter book information. (Yes, these would probably be `ModelForm`s, but suspend your disbelief long enough for me to make my point.) Here's the basic form:
     7class BookForm(forms.Form):
     8    title = forms.CharField(max_length=80)
     9    author = forms.CharField(max_length=40)
     10    publisher = forms.CharField(max_length=40)
     11    copyright = forms.IntegerField()
     14While this form works for most books, there are some that it has trouble with. Translations, for example, have a translator in addition to the author. Through the magic of inheritance, you can just create a new class that adds the translator field and inherits the rest:
     16class TranslationForm(BookForm):
     17    translator = forms.CharField(max_length=40)
     20Unfortunately, when you try to display a `TranslationForm`, the translator field will end up at the bottom, below the publisher and copyright. Clearly it makes more sense for it to appear right after the author. You could throw up your hands, forget about inheritance and create a whole new `TranslationForm` that doesn't inherit from `BookForm`.
     22But if you did that, you'd be RYing, and we all know that Django strives to be a DRY framework. You could also specify the order of the fields in your template, but that seems like a lot more work than just putting `{{ form }}`.
     24There is an easier way. It turns out that all the fields in a form are stored in a `SortedDict`, a nice little data structure defined in `django.utils.datastructures`. The key difference between a regular `dict` and a `SortedDict` is that the latter maintains a list of its keys in the order they were added in an attribute called `keyOrder`. Replace `keyOrder` with the order you want, and you've fooled the `SortedDict`. Here, then, is a `TranslationForm` that's much less cumbersome than the alternatives:
     26class TranslationForm(BookForm):
     27    translator = forms.CharField(max_length=40)
     29    def __init__(self, *args, **kwargs):
     30        super(TranslationForm, self).__init__(*args, **kwargs)
     31        self.fields.keyOrder = ['title', 'author', 'translator', 'publisher', 'copyright']
     33Simple as that and you've got the order you wanted.
Back to Top