1
votes

I'm looking for a more elegant way to populate an App Engine Datastore entity from a WTForms model without assigning each property one at a time.

I remember seeing something similar done with getattr().

WTForm model for the edit profile page, like this:

class EditProfile(Form):
    first_name = StringField('First Name')
    last_name = StringField('Last Name')
    [...]

NDB model for users:

class User(ndb.Model):
    first_name = ndb.StringProperty()
    last_name = ndb.StringProperty()
    [...]

Note: all property names of both models identical.

Request handler for the edit profile page:

@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():
    form = EditProfile()

    if request.method == 'POST':
        if form.validate_on_submit():
            user = User.get_by_id(session.get('user_id'))

            ???

            user.put()
2

2 Answers

3
votes

Use populate_obj method.

Populates the attributes of the passed obj with data from the form’s fields.

form.populate_obj(user)
user.put()
2
votes

Something like...:

for field in dir(form):
    if field.startswith('_'): continue  # skip private stuff
    if not user.hasattr(field): continue  # skip non-corresponding stuff
    value = getattr(form, field)
    setattr(user, field, value)

There may be subtleties e.g about types (requiring type conversion for certain fields) or even fancier ones (maybe we need to work with User.hasattr, i.e, on the class, not the instance), but this is a generally good starting point for transcribing equally-named, compatibly-typed fields between two different kinds of class instances.