我目前在使用flush
下的SQLAlchemy commit
的{{1}}(或依赖于它的session
)方法时遇到永久性问题
Flask Alchemy
部分始终因flush
而失败(以下是全栈错误)。直接运行时,来自引擎的sqlalchemy.exc.ResourceClosedError: This transaction is closed
调用以及使用insert
构建器检索数据的工作原理。
此外,删除某项操作正常(通过query
和session.delete(model)
)
这是代码失败:
session.commit()
SQLAlchemy通过以下方式初始化
:roles_put = Blueprint('roles_put', __name__)
@roles_put.route('<role_id>', methods=['PUT'])
def role_update(role_id):
role = Role.query.get(role_id)
if not role:
role = Role.query.filter_by(name=role_id).first()
if not role:
raise IDNotFoundError()
print(role)
role.set_data(
request.form,
[
'name', 'manage_user', 'manage_video', 'manage_comment', 'manage_avatar', 'manage_channel', 'manage_reward',
'manage_role', 'manage_top', 'manage_calendar', 'manage_setting', 'validate_video', 'moderate_comment',
]
)
MainAPI.db.session.add(role)
MainAPI.db.session.flush()
MainAPI.db.session.commit()
# if not role.save():
# raise UpdateError()
return jsonify(role.serialize())
角色模型:
app = Flask('Name')
def init_db(app, config):
"""
Init SQLAlchemy DB
"""
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://%s:%s@%s/%s' % (
config.get('database', 'user'),
config.get('database', 'password'),
config.get('database', 'host'),
config.get('database', 'database')
)
print(app.config['SQLALCHEMY_DATABASE_URI'])
MainApi.db = SQLAlchemy(app)
完整错误堆栈:
class RoleModel(MainApi.db.Model):
__tablename__ = 'roles'
LOCKED_ROLE_NAMES = ['guest', 'admin', 'logged', 'public']
id = MainApi.db.Column(MainApi.db.Integer, primary_key=True, unique=True, autoincrement=True)
name = MainApi.db.Column(MainApi.db.String(40), nullable=False, unique=True)
# manage rights
manage_user = MainApi.db.Column(MainApi.db.Boolean, nullable=False, default=False)
moderate_comment = MainApi.db.Column(MainApi.db.Boolean, nullable=False, default=False)
created_at = MainApi.db.Column(MainApi.db.DateTime, nullable=False, default=datetime.utcnow)
last_updated_at = MainApi.db.Column(MainApi.db.DateTime, nullable=True)
created_by = MainApi.db.Column(
MainApi.db.Integer,
MainApi.db.ForeignKey(
'users.id', ondelete='RESTRICT', onupdate='CASCADE'
),
nullable=True
)
last_updated_by = MainApi.db.Column(
MainApi.db.Integer,
MainApi.db.ForeignKey(
'users.id', ondelete='CASCADE', onupdate='CASCADE'
), nullable=True
)
users = MainApi.db.relationship(
'UserModel', foreign_keys='UserModel.role_id',
back_populates='role'
)
@staticmethod
def is_allowed(action, role):
"""
Check if user having role can make action
:param action: action name
:type action: str
:param role: user role
:type role: int|str|RoleModel
:return:
"""
if isinstance(role, str):
role = RoleModel.query.filter_by(name=role).first()
elif isinstance(role, int):
role = RoleModel.query.get(role)
if not isinstance(role, RoleModel):
raise Exception
return getattr(role, action.strip().replace(' ', '_'))
@staticmethod
def get_role_id(role):
"""
Check if user having role can make action
:param role: user role
:type role: int|str|RoleModel
:return: role id
:rtype: int
"""
if isinstance(role, str):
role = RoleModel.query.filter_by(name=role).first()
elif isinstance(role, int):
role = RoleModel.query.get(role)
if not isinstance(role, RoleModel):
raise Exception
return role.id
def serialize(self):
users = [u.serialize() for u in self.users] if self.users else []
return {
'id': self.id,
'name': self.name,
'manage_user': self.manage_user,
'moderate_comment': self.moderate_comment,
'created_at': self.created_at,
'last_updated_at': self.last_updated_at,
'created_by': self.created_by,
'last_updated_by': self.last_updated_by,
'users': users,
}
@event.listens_for(RoleModel.name, 'set', propagate=True)
def before_set_name(_target, value, old, _initiator):
print(_initiator)
print(request.url)
if request and 'roles/init' not in request.url:
if old in RoleModel.LOCKED_ROLE_NAMES or value in RoleModel.LOCKED_ROLE_NAMES:
raise UnauthorizedError()
@event.listens_for(RoleModel, 'before_insert', propagate=True)
def receive_before_insert(_mapper, _connection, target):
user = Registry.registered('current-user-id')
target.created_at = datetime.utcnow()
if user:
target.created_by = user
@event.listens_for(RoleModel, 'before_update', propagate=True)
def receive_before_update(_mapper, _connection, target):
user = Registry.registered('current-user-id')
target.updated_at = datetime.utcnow()
if user:
target.updated_by = user
版本:
感谢任何在这里提出建议的人。
答案 0 :(得分:0)
最后解决了。
问题出在模型before_insert
和before_update
回调中。
尝试从current-user-id
检索Flask.g
似乎对session
产生了奇怪的影响。当然,这与我的Registry
类实现的工作方式有关。