Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't a simple dictionary populate obj properly for form = myForm(obj=dict)?

Tags:

wtforms

I'm having trouble populating a form using a dictionary:

        row = {'firstname':'Bob', 'lastname': "Smith",
               'email': '[email protected]', 'phone': '512.999.1212'}
        form = RolodexEntry(obj=row)

doesn't put any data into form (i.e. form.firstname.data = None after the preceding).

The top of the form definition is shown below. I'm at a loss for what to try next. The form documentation just says:

obj – If formdata is empty or not provided, this object is checked for attributes matching form field names, which will be used for field values.

class RolodexEntry(Form):
    firstname  = TextField('First Name',[validators.length(max=40)],
                           filters=[strip_filter])
    lastname   = TextField('Last Name', [validators.length(max=40)],
                           filters=[strip_filter])
    email      = TextField('Email',     [validators.Optional(),
                                         validators.length(max=25),
                                         validators.Email()],
                           filters=[strip_filter])
    ...
like image 539
pgoetz Avatar asked May 01 '13 21:05

pgoetz


4 Answers

This answer included for completeness. As pointed out by Sean Vieira, WTForms is using getattr to get attribute names, which doesn't work with dictionaries. Using the accepted answer from

Convert Python dict to object?

This also works:

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

row = {'firstname':'Bob', 'lastname': "Smith",
       'email': '[email protected]', 'phone': '512.999.1212'}
rowobj = Struct(**row)
form = RolodexEntry(obj=rowobj)
like image 117
pgoetz Avatar answered Nov 03 '22 19:11

pgoetz


The issue is the WTForms only use getattr to check if the field name exists in obj (it doesn't try to invoke __getitem__). You can use a namedtuple instead of a dictionary or you can pass in your data as keyword arguments (form = RolodexEntry(**row)).

like image 18
Sean Vieira Avatar answered Nov 03 '22 20:11

Sean Vieira


Albeit this question was asked a while ago, I suggest to see Sean Vieira's answer to a duplicate of this question. As explained in his answer, any class with an interface including getlist will be accepted by the wtforms.Form constructor.

like image 1
Philippe Hebert Avatar answered Nov 03 '22 19:11

Philippe Hebert


according to Sean Vieira 's answer and in my flask app, I write my code like this:

from collections import namedtuple
UpdateSchema= namedtuple('UpdateSchema', ['name', 'real_name', 'email', 'phone'])
update_schema = UpdateSchema(
    name= current_user.name,
    real_name=current_user.job_hunter.real_name,
    email=current_user.email,
    phone=current_user.job_hunter.phone
)
form = UpdateJobHunterForm(obj=update_schema)

my app is a job find website, and I suggest you do not write like :

update_schema = dict(
    'name': current_user.name,
    'real_name':current_user.job_hunter.real_name,
    'email':current_user.email,
    'phone':current_user.job_hunter.phone
)
form = UpdateJobHunterForm(**update_schema)

In this way, if I want to upload a file, the request wont get the file filed data, so do not write in the second way!!

like image 1
Carl Lee Avatar answered Nov 03 '22 19:11

Carl Lee