0

I'm trying to modify an existing row of data from the database by using the form it was submitted with. This route and template properly loads the data into my form:

@app.route('/match/<int:match_id>/edit', methods=['GET', 'POST'])
@login_required
def match_edit(match_id):
    match = db.session.query(MatchScore).get(match_id)
    if match is None:
        abort(404)
    form = MatchScoringForm(request.values, obj=match)
    form.team.choices = [
            (a.id, a.number) for a in Teams.query.filter(
            Teams.id == match.teams)]
    if request.method == 'POST' and form.validate_on_submit():
        form.populate_obj(match)
        db.session.commit()
        flash('Score Updated Successfully')
        return redirect(url_for('match'))
    elif request.method == 'GET':
        return render_template('match.html',
                               form=form,
                               match=match)

And the form control line from the template:

form action="{{ url_for('match_edit', match_id=match.id) }}" method="post"

However, I'm getting an error on the form.populate_obj line above in the route when trying to submit an update:

AttributeError
AttributeError: 'int' object has no attribute '_sa_instance_state'

Traceback (most recent call last)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/flask_login/utils.py", line 228, in decorated_view
return func(*args, **kwargs)
File "/Users/rahm/PycharmProjects/VVScouting/app/views.py", line 341, in match_edit
form.populate_obj(match)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/wtforms/form.py", line 96, in populate_obj
field.populate_obj(obj, name)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/wtforms/fields/core.py", line 327, in populate_obj
setattr(obj, name, self.data)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 224, in __set__
instance_dict(instance), value, None)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 812, in set
value = self.fire_replace_event(state, dict_, value, old, initiator)
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 834, in fire_replace_event
self._replace_token or self._init_append_or_replace_token())
File "/Users/rahm/PycharmProjects/VVScouting/env/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 86, in set_
newvalue_state = attributes.instance_state(newvalue)
AttributeError: 'int' object has no attribute '_sa_instance_state'

However, if I just brute force the sql, it works fine:

@app.route('/match/<int:match_id>/edit', methods=['GET', 'POST'])
@login_required
def match_edit(match_id):
    match = db.session.query(MatchScore).get(match_id)
    if match is None:
        abort(404)
    form = MatchScoringForm(request.values, obj=match)
    form.team.choices = [
            (a.id, a.number) for a in Teams.query.filter(
            Teams.id == match.teams)]
    if request.method == 'POST' and form.validate_on_submit():
        postdata = request.values
        t_capball_tried = True if 't_capball' in request.form else False
        sql_text = '''update MatchScore set match_number="%s", \
                        a_center_vortex=%d, \
                        a_center_vortex_miss=%d, \
                        a_beacon=%d, \
                        a_beacon_miss=%d, \
                        a_capball=%d, \
                        a_park=%d, \
                        t_center_vortex=%d, \
                        t_center_vortex_miss=%d, \
                        t_beacon=%d, \
                        t_beacons_pushed=%d, \
                        t_capball=%d, \
                        t_capball_tried=%d, \
                        a_score=%d, \
                        t_score=%d, \
                        total_score=%d, \
                        match_notes="%s" where id = %d''' % (
            str(postdata['match_number']),
            int(postdata['a_center_vortex']),
            int(postdata['a_center_vortex_miss']),
            int(postdata['a_beacon']),
            int(postdata['a_beacon_miss']),
            int(postdata['a_capball']),
            int(postdata['a_park']),
            int(postdata['t_center_vortex']),
            int(postdata['t_center_vortex_miss']),
            int(postdata['t_beacon']),
            int(postdata['t_beacons_pushed']),
            int(postdata['t_capball']),
            t_capball_tried,
            int(postdata['a_score']),
            int(postdata['t_score']),
            int(postdata['total_score']),
            str(postdata['match_notes']),
            match_id)
        result = db.engine.execute(sql_text)
        # form.populate_obj(match)
        # db.session.commit()
        flash('Score Updated Successfully')
        return redirect(url_for('match_edit', match_id=match_id))

Any pointers on fixing my approach or a better approach would be helpful.

Jason Rahm
  • 670
  • 3
  • 14
  • It might be similar to this: http://stackoverflow.com/questions/16151729/attributeerror-int-object-has-no-attribute-sa-instance-state Check if you are passing primary keys instead of ORM objects anywhere. – Rohanil Mar 03 '17 at 05:34
  • If it does not solve your problem, please tell more about your `Teams `, `MatchScore` and `MatchScoringForm` classes. – Rohanil Mar 03 '17 at 05:47
  • I don't think that is the case here, but I could be mistaken. Only passing that one match record to the form, which loads properly in the form on GET. It's just POST that is the problem. I'll update the op with the class info. – Jason Rahm Mar 03 '17 at 06:51
  • I did get it working, but super hacky and I know I'm missing something simple and stupid. – Jason Rahm Mar 03 '17 at 20:33

0 Answers0