Как вставить новый объект в одну таблицу после обновления другой таблицы в flask-sqlalchemy

#python #flask #flask-sqlalchemy

#python #flask #flask-sqlalchemy

Вопрос:

Я использую Flask-Sqlalchemy orm в своем проекте.

Я должен вставлять новый объект в одну таблицу всякий раз, когда происходит обновление другой таблицы.Итак, я выбрал models_committed signal .Но объект не вставляется.

 @models_committed.connect_via(app)
def on_models_committed(sender, changes):
    print "signal",changes
    for obj, change in changes:
        if obj.__table__.strip() == 'task':
            print "works"
            obj = TaskHistory(task_id=target.id, task_status_id=target.task_status_id,  reason=target.reason)
            print "History Object",obj
            db.session.add(obj)
            db.session.commit()
 

Трассировка:

Краткая версия:

 **sqlalchemy.exc.InvalidRequestError
InvalidRequestError: This session is in 'committed' state; no further SQL can be emitted within this transaction.**
 

Длинная версия:

 Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask_debugtoolbar/__init__.py", line 125, in dispatch_request
    return view_func(**req.view_args)
  File "/usr/lib/python2.7/cProfile.py", line 149, in runcall
    return func(*args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/base.py", line 37, in inner
    return f(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/base.py", line 37, in inner
    return f(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/base.py", line 37, in inner
    return f(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/base.py", line 37, in inner
    return f(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/model/base.py", line 345, in edit
    pk=self.get_pk(instance), instance=instance)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/base.py", line 169, in render
    return render_template(template, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask/templating.py", line 128, in render_template
    context, ctx.app)
  File "/usr/local/lib/python2.7/dist-packages/flask/templating.py", line 110, in _render
    rv = template.render(context)
  File "/usr/share/pyshared/jinja2/environment.py", line 969, in render
    return self.environment.handle_exception(exc_info, True)
  File "/usr/share/pyshared/jinja2/environment.py", line 742, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/templates/admin/model/edit.html", line 3, in top-level template code
    {% set name = admin_view.get_display_name() %}
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/templates/admin/layout.html", line 21, in top-level template code
    {% block page_body %}
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/templates/admin/layout.html", line 70, in block "page_body"
    {% block body %}{% endblock %}
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/templates/admin/model/edit.html", line 26, in block "body"
    {{ lib.render_form(form, extra(), admin_view.can_edit, admin_view.can_delete) }}
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/templates/admin/_macros.html", line 192, in template
    {{ render_formfield(form) }}
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/templates/admin/_macros.html", line 180, in template
    {{ render_ff(form._fields[field_name]) }}
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/templates/admin/_macros.html", line 142, in template
    {{ ff(class=class) }}
  File "/usr/local/lib/python2.7/dist-packages/wtforms/fields/core.py", line 139, in __call__
    return self.widget(self, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/flask_superadmin/form.py", line 96, in __call__
    return super(ChosenSelectWidget, self).__call__(field, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/wtforms/widgets/core.py", line 243, in __call__
    for val, label, selected in field.iter_choices():
  File "/usr/local/lib/python2.7/dist-packages/wtforms/ext/sqlalchemy/fields.py", line 108, in iter_choices
    for pk, obj in self._get_object_list():
  File "/usr/local/lib/python2.7/dist-packages/wtforms/ext/sqlalchemy/fields.py", line 101, in _get_object_list
    self._object_list = list((text_type(get_pk(obj)), obj) for obj in query)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 2404, in __iter__
    return self._execute_and_instances(context)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 2417, in _execute_and_instances
    close_with_result=True)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/query.py", line 2408, in _connection_from_session
    **kw)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 843, in connection
    close_with_result=close_with_result)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 847, in _connection_for_bind
    return self.transaction._connection_for_bind(engine)
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 298, in _connection_for_bind
    self._assert_active()
  File "/usr/local/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 192, in _assert_active
    "This session is in 'committed' state; no further "
InvalidRequestError: This session is in 'committed' state; no further SQL can be emitted within this transaction.
 

Не могли бы вы помочь мне в решении этой проблемы?

Инструменты, которые я использую: Python 2.7, Flask, SQLAlchemy

Ответ №1:

 @models_committed.connect_via(app)
def on_models_committed(sender, changes):
    db_name = app.config["DB_NAME"]
    db_user = app.config["DB_USER"]
    db_pwd = app.config["DB_PWD"]
    conn = psycopg2.connect("dbname='%s' user='%s' host='localhost' password='%s'" %(db_name, db_user, db_pwd))
    query = "INSERT INTO task_history(task_id, task_status_id, updated_on, updated_by, reason)"  
        "VALUES (%s, %s, '%s', %s, '%s')"
    cur = conn.cursor()
    for obj, change in changes:
        if str(obj.__table__).strip() == 'task':
            cur.execute(query % (obj.id, obj.task_status_id, "now()", 2, "Thats it"))
            conn.commit()
 

Мое решение (я ответил на свой вопрос):

  1. создано отдельное соединение с использованием psycopg2
  2. Вставлен новый объект

Ответ №2:

Это не решение, вы только обошли проблему. Вы должны посмотреть, почему вы переназначили obj в цикле for. Удаление этого переназначения, вероятно, решило бы вашу проблему.