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

5

10

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])
    ...
Butterfly answered 1/5, 2013 at 21:53 Comment(0)
C
18

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)).

Clupeoid answered 2/5, 2013 at 1:57 Comment(1)
Overriding process is a bad idea. One can simply pass the dictionary as **row to the Form constructor if a dict is required.Luht
B
10

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)
Butterfly answered 2/5, 2013 at 21:19 Comment(1)
This worked for me over the accepted answer. Also in my case I had to add RolodexEntry(formdata=None, obj=rowobj).Inconveniency
B
1

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.

Buchalter answered 13/5, 2016 at 17:38 Comment(0)
S
1

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!!

Sym answered 3/5, 2018 at 9:16 Comment(0)
N
0

When I was using flask_wtf, I found Flask's form class was messing me up. I think this was the same issue from @wgwz's comment to @pgoetz's answer. The Flask form automatically populated formdata with data from the request. Since my "RolodexEntry" was a FormField embedded in a larger Form, the automatically-populated formdata was invalid. To try to fix this, instead of subclassing Flask's Form, I subclassed wtforms' Form.

Negativism answered 20/5, 2016 at 23:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.