Flask-Sqlalchemy autocommit UPDATE при вставке нескольких экземпляров? - PullRequest
0 голосов
/ 24 ноября 2018

Я пытаюсь сохранить некоторые столбцы (например, теги, модели) со строкой в ​​кодировке JSON.

И я всегда надеюсь сохранить их в декодированном виде.

Я прочитал некоторые ссылки надобавить конфиги, чтобы отключить автокоммит и автозапуск, но это не работает.

Пока экземпляр был добавлен в db.session, а затем изменил значение, orm все еще пытается зафиксировать операцию UPDATE, а затем вызвать TypeError.

Вот мой код.

`` `python

import json
from sqlalchemy import orm
from flask_sqlalchemy import SQLAlchemy

session_options = dict(
    bind=None,
    autoflush=False,
    autocommit=False,
    expire_on_commit=False,
)
db = SQLAlchemy(session_options=session_options)


class Sample(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    # tags, models : string of json.dumps(array)
    tags = db.Column(db.String(128), default='')
    models = db.Column(db.String(128), default='')

    def __init__(self, **kwargs):
        cls = self.__class__
        super(cls, self).__init__(**kwargs)
        self.formatting()

    @orm.reconstructor
    def init_on_load(self):
        self.formatting()

    def formatting(self):
        self.tags = json.loads(self.tags)
        self.models = json.loads(self.models)

    def save(self):
        self.tags = json.dumps(self.tags)
        self.models = json.dumps(self.models)

        db.session.add(self)
        db.session.commit()

        self.formatting()
        ## fixme !!!
        ## formatting after saved will cause auto-commit and raise TypeError 

` ``

Спасибо:)

ps: Flask-SQLAlchemy == 2.3.2

1 Ответ

0 голосов
/ 25 ноября 2018

Эта ошибка возникла из-за отсутствия db.session.close() после db.session.commit()

Мне сказали, что db.session.close() автоматически вызывается в db.session.commit().И настоящее отрицает мое познание.

И я пытаюсь сослаться на исходный код sqlalchmey, и затем я обнаружил, что db.session является экземпляром sqlalchemy.orm.scoping.scoped_session, НЕ sqlalchemy.orm.SessionTransaction.

Вот исходный код в sqlalchemy.orm.SessionTransaction

`` `python

def commit(self):
    self._assert_active(prepared_ok=True)
    if self._state is not PREPARED:
        self._prepare_impl()

    if self._parent is None or self.nested:
        for t in set(self._connections.values()):
            t[1].commit()

        self._state = COMMITTED
        self.session.dispatch.after_commit(self.session)

        if self.session._enable_transaction_accounting:
            self._remove_snapshot()

    self.close()
    return self._parent

` ``

Это действительно сбивает с толку.


Если вы хотите повторить эту ошибку, вот тестовый код:

`` `python

"""
# snippet for testing <class:Sample>
"""

from flask import Flask
app = Flask(__name__)
app.config.from_mapping(
    SQLALCHEMY_ECHO=True,
    SQLALCHEMY_TRACK_MODIFICATIONS=False,
    SQLALCHEMY_DATABASE_URI='sqlite:///test_orm.sqlite.db',
)

db.init_app(app=app)
db.app = app
db.create_all()

d1 = dict(
    tags='["python2","flask"]',
    models='["m1"]'
)
m1 = Sample(**d1)
print(1111, type(m1.tags), m1.tags)
m1.save()
print(1112, type(m1.tags), m1.tags)
dm1 = Sample.query.filter(Sample.id == m1.id).all()[0]
print(1113, dm1, type(dm1.tags), dm1.tags)

## fixme[Q1] !!!
## if not continue with $d2, it won't raise error of UPDATE $d1

d2 = dict(
    tags='["python3","flask"]',
    models='["m2", "m3"]'
)
m2 = Sample(**d2)
print(2221, type(m2.tags), m2.tags)

## fixme[Q1] !!!
# db.session.close()
## If session was not closed, error raise here.

m2.save()
print(2222, type(m2.tags), m2.tags)
dm2 = Sample.query.filter(Sample.id == m2.id).all()[0]
print(2223, dm2, type(dm2.tags), dm2.tags)

` ``

СпасибоВы за то, что читаете, хотите развеять то же замешательство.

...