SQLAlchemy с Flask db.session.commit () не работает - PullRequest
1 голос
/ 09 июля 2020

У меня проблема, похожая на здесь , поэтому вставка новых записей в db работает, но не обновляется.

Разница в том, что я не получаю сообщения об ошибке, и я ДЕЛАЮ db.create_all() каждый раз, когда я запускаю свое приложение.

  1. Я инициирую app_context и db:

    <code> app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://karolina@127.0.0.1/tests_results'
     app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
     db.init_app(app)
     app_context = app.app_context()
     DataBaseController.init(app_context)
  2. Затем я запускаю потоков в основном приложении с параметром app_context в качестве параметра, тогда у меня есть метод, который создает запись, и каждый поток, который является функцией, которая в конце - всегда обновляет одну запись в базе данных.

update_test_result метод из DataBaseController:

@staticmethod
    def update_test_result(app_context):
        with app_context:
            db.session.commit()

EDIT: подсказка с несколькими экземплярами db / текущий сеанс может быть - хотя я действительно не понимаю, как это должно быть сделано. Мне кажется, что, возможно, вместе с appcontext, я должен передать также db из app.py - в крайнем отчаянии я решил передать db и appcontext из основного приложения практически каждой функции - безрезультатно. . Что касается того, как я это делаю сейчас:

a) У меня есть скрипт database.py, который объявляет «пустой» db (без модели):

<code>from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

b) Затем у меня есть models.py, который импортирует db из приведенного выше и объявляет модель следующим образом:

from database_management.database import db

class Result(db.Model):
    id = db.Column(db.String(150), primary_key=True)
    result = db.Column(db.Boolean)
    status = db.Column(db.String(20))

c) Наконец, я подключаю db к модели, которую я создал в основном app, и я передаю app_context каждому потоку, который обновляет записи в db.

Main app.py:

db.init_app(app)
app_context = app.app_context()
DataBaseController.init(app_context, db)

Вот как я инициирую db в DataBaseController:

from database_management.database import db
@staticmethod
    def init(app_context, db):
        with app_context:
            db.create_all()
            DataBaseController.create_bots()
            db.session.commit()

L oop из основного приложения:

test_cases = TestCasesLoader.split_test_cases(dialog_cases, db, app_context)  # here I create records
    threads_list = list()
    for test_case in test_cases[:10]:
        threads_list.append(Thread(target=test_case.run_test_case, args=(db, app_context, bot_config)))  # and here I update them

Создание записей:

@staticmethod
    def split_test_cases(dialog_cases, db, appcontext):
        db_name = dialog_cases.get("bot_name")
        for test_case in dialog_cases.get("test_case_list"):
            test_result = DataBaseController.get_test_result(db, appcontext, test_id)
            if test_result:
                DataBaseController.clean_result_data_in_db(db, appcontext, test_result)
            else:
                test_result = {
                    'id': test_id,
                    'status': 'IN_PROGRESS'
                }
                test_result = Result(test_result)
                DataBaseController.add_result_to_db(db, appcontext, test_result)

Создание в DataBaseController:

@staticmethod 
    def add_result_to_db(db, appcontext, result):
        with appcontext:
            db.session.add(result)
            db.session.commit()

Обновление в ветке:

def update_passed_result_in_db(self, appcontext):
    print("passed")
    result = DataBaseController.get_test_result(appcontext, self.test_id)
    result.result = self.test_passed
    result.status = 'DONE'
    with appcontext:
        db.session.commit()

А вот и обновление в DataBaseController:

from database_management.database import db

def update_passed_result_in_db(self, db, appcontext, human_said):
        result = DataBaseController.get_test_result(db, appcontext, self.test_id)
        result.result = self.test_passed
        result.status = 'DONE'
        with appcontext:
            db.session.commit()

Пожалуйста, дайте мне знать, если у вас есть идеи, что я делаю неправильно. Что супер интересно, когда поэкспериментировал вот так:

def update_passed_result_in_db(self, db, appcontext):   
result = DataBaseController.get_test_result(db, appcontext, self.test_id)
        cprint.err(type(result))
        result.id = self.test_id
        result.result = self.test_passed
        result.status = 'working'
        with appcontext:
            db.session.add(result)
            db.session.commit()

Запись добавлена ​​правильно ...

1 Ответ

1 голос
/ 10 июля 2020

Проблема действительно связана с контекстом приложения.

Это не сработало:

result = db.session.query(Result).filter_by(id=test_id).first()
result.id = self.test_id
result.result = self.test_passed
result.status = 'working'
with appcontext:
    db.session.commit()

Это сработало:

result_data = {
    'status': 'working'
}
with appcontext:
    result = Result.query.filter_by(id=self.test_id).update(result_data)
    db.session.commit()

Это потому, что запрос данных и их обновление должны выполняться в рамках одного контекста приложения, а не отдельно.

...