Question

In python is guaranteed that the order of attributes in a class is maintained? How this is guaranteed? Where in manual is specified?

This defines the fields declaratively as class attributes:

class MyForm(Form):
    first_name = TextField(u'First Name', validators=[validators.required()])
    last_name  = TextField(u'Last Name', validators=[validators.optional()])
    ...


def get(self):
    form = MyForm(self.request.arguments)
    form=form
    self.render('forms.html', form=form)

First name will be always the first item and the last name the second, even if i have n items?

Was it helpful?

Solution

No, the order of attributes is normally not guaranteed, as Python stores attributes in a dictionary.

Instead, wtforms uses special tricks to detect in what order fields were defined, that work around this. Every time you create a Field object, a counter is incremented and a unique number is assigned to the field instance. This makes the objects orderable:

class UnboundField(object):
    _formfield = True
    creation_counter = 0

    def __init__(self, field_class, *args, **kwargs):
        UnboundField.creation_counter += 1
        # [...]
        self.creation_counter = UnboundField.creation_counter

So the Field instances have a creation_counter value that is incremented each time a new field is added to a form.

The FormMeta class then uses that value on the fields to sort them in the correct order:

fields.sort(key=lambda x: (x[1].creation_counter, x[0]))

OTHER TIPS

A new class is created by instantiating a metaclass, pretty much like you create a new instance object by instantiating the class. A class statement like:

class MyForm(Form):
    first_name = TextField(u'First Name', validators=[validators.required()])
    last_name  = TextField(u'Last Name', validators=[validators.optional()])    

Is equivalent to the following call, where type is the default python metaclass:

MyForm = type('MyForm', (Form,), {'first_name': TextField(u'First Name', validators=[validators.required()]), 
                                  'last_name': TextField(u'Last Name', validators=[validators.optional()])}

Since the class namespace is passed forward as a dict, and dicts have an arbitrary ordering, the order is not preserved.

One way to keep the order recorded somewhere is by having the TextField class itself registering the order in which it was called for each set of parameters. Then you can recover the order in which the fields were declared. This is probably what Django does under the hood.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top