问题复现:
1、首先代码中,不同的接口,需要同一个的权限控制,这在业务上也较为常见。比如:getbook和getbooks,都增加login和permission注解,且permission权限项一样。
`
@book_api.route("/")
@permission_meta(name="查看图书", module="图书")
@login_required
@api.validate(
resp=DocResponse(BookNotFound, r=BookOutSchema),
tags=["图书"],
)
def get_book(id):
"""
获取id指定图书的信息
"""
book = Book.get(id=id)
if book:
return book
raise BookNotFound
@book_api.route("")
@permission_meta(name="查看图书", module="图书")
@login_required
@api.validate(
resp=DocResponse(r=BookSchemaList),
tags=["图书"],
)
def get_books():
"""
获取图书列表
"""
return Book.get(one=False)
2、重新初始化数据库,报错。
flask db init --force
此操作将清空数据,是否继续? [y/N]: y
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1819, in _execute_context
self.dialect.do_execute(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute
cursor.execute(statement, parameters)
sqlite3.IntegrityError: UNIQUE constraint failed: lin_permission.name, lin_permission.module
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/bin/flask", line 8, in
sys.exit(main())
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/flask/cli.py", line 601, in main
return super().main(args, kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, ctx.params)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 760, in invoke
return __callback(args, kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, *kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/flask/cli.py", line 445, in decorator
return __ctx.invoke(f, args, kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 760, in invoke
return callback(*args, **kwargs)
File "/Users/zhouchengbo/PycharmProjects/lin-cms-starter/app/cli/init.py", line 21, in db_init
_db_init(force)
File "/Users/zhouchengbo/PycharmProjects/lin-cms-starter/app/cli/db/init.py", line 44, in init
manager.sync_permissions()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/lin/manager.py", line 177, in sync_permissions
_sync_permissions(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/contextlib.py", line 126, in exit
next(self.gen)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/lin/db.py", line 482, in auto_commit
raise e
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/lin/db.py", line 479, in auto_commit
self.session.commit()
File "", line 2, in commit
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 1451, in commit
self._transaction.commit(_to_root=self.future)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 829, in commit
self._prepare_impl()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 808, in _prepare_impl
self.session.flush()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 3383, in flush
self._flush(objects)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 3523, in _flush
transaction.rollback(_capture_exception=True)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 70, in exit_
compat.raise(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 3483, in _flush
flush_context.execute()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/unitofwork.py", line 456, in execute
rec.execute(self)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/unitofwork.py", line 630, in execute
util.preloaded.orm_persistence.save_obj(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/persistence.py", line 245, in save_obj
_emit_insert_statements(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/persistence.py", line 1238, in _emit_insert_statements
result = connection._execute_20(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1631, in _execute_20
return meth(self, args_10style, kwargs_10style, execution_options)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/sql/elements.py", line 332, in _execute_on_connection
return connection._execute_clauseelement(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1498, in _execute_clauseelement
ret = self._execute_context(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1862, in _execute_context
self._handle_dbapi_exception(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 2043, in _handle_dbapiexception
util.raise(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1819, in _execute_context
self.dialect.do_execute(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: lin_permission.name, lin_permission.module
[SQL: INSERT INTO lin_permission (delete_time, is_deleted, name, module, mount) VALUES (?, ?, ?, ?, ?)]
[parameters: (None, 0, '查看图书', '图书', 1)]
(Background on this error at: https://sqlalche.me/e/14/gkpj)
`
问题复现: 1、首先代码中,不同的接口,需要同一个的权限控制,这在业务上也较为常见。比如:getbook和getbooks,都增加login和permission注解,且permission权限项一样。 ` @book_api.route("/")
@permission_meta(name="查看图书", module="图书")
@login_required
@api.validate(
resp=DocResponse(BookNotFound, r=BookOutSchema),
tags=["图书"],
)
def get_book(id):
"""
获取id指定图书的信息
"""
book = Book.get(id=id)
if book:
return book
raise BookNotFound
@book_api.route("") @permission_meta(name="查看图书", module="图书") @login_required @api.validate( resp=DocResponse(r=BookSchemaList), tags=["图书"], ) def get_books(): """ 获取图书列表 """ return Book.get(one=False)
2、重新初始化数据库,报错。
flask db init --force 此操作将清空数据,是否继续? [y/N]: y Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1819, in _execute_context self.dialect.do_execute( File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute cursor.execute(statement, parameters) sqlite3.IntegrityError: UNIQUE constraint failed: lin_permission.name, lin_permission.moduleThe above exception was the direct cause of the following exception:
Traceback (most recent call last): File "/Library/Frameworks/Python.framework/Versions/3.9/bin/flask", line 8, in
sys.exit(main())
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/flask/cli.py", line 995, in main
cli.main(args=sys.argv[1:])
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/flask/cli.py", line 601, in main
return super().main(args, kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, ctx.params)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 760, in invoke
return __callback(args, kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/decorators.py", line 26, in new_func
return f(get_current_context(), *args, *kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/flask/cli.py", line 445, in decorator
return __ctx.invoke(f, args, kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/click/core.py", line 760, in invoke
return callback(*args, **kwargs)
File "/Users/zhouchengbo/PycharmProjects/lin-cms-starter/app/cli/init.py", line 21, in db_init
_db_init(force)
File "/Users/zhouchengbo/PycharmProjects/lin-cms-starter/app/cli/db/init.py", line 44, in init
manager.sync_permissions()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/lin/manager.py", line 177, in sync_permissions
_sync_permissions(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/contextlib.py", line 126, in exit
next(self.gen)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/lin/db.py", line 482, in auto_commit
raise e
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/lin/db.py", line 479, in auto_commit
self.session.commit()
File "", line 2, in commit
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 1451, in commit
self._transaction.commit(_to_root=self.future)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 829, in commit
self._prepare_impl()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 808, in _prepare_impl
self.session.flush()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 3383, in flush
self._flush(objects)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 3523, in _flush
transaction.rollback(_capture_exception=True)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 70, in exit_
compat.raise(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/session.py", line 3483, in _flush
flush_context.execute()
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/unitofwork.py", line 456, in execute
rec.execute(self)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/unitofwork.py", line 630, in execute
util.preloaded.orm_persistence.save_obj(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/persistence.py", line 245, in save_obj
_emit_insert_statements(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/orm/persistence.py", line 1238, in _emit_insert_statements
result = connection._execute_20(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1631, in _execute_20
return meth(self, args_10style, kwargs_10style, execution_options)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/sql/elements.py", line 332, in _execute_on_connection
return connection._execute_clauseelement(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1498, in _execute_clauseelement
ret = self._execute_context(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1862, in _execute_context
self._handle_dbapi_exception(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 2043, in _handle_dbapiexception
util.raise(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1819, in _execute_context
self.dialect.do_execute(
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 732, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: lin_permission.name, lin_permission.module
[SQL: INSERT INTO lin_permission (delete_time, is_deleted, name, module, mount) VALUES (?, ?, ?, ?, ?)]
[parameters: (None, 0, '查看图书', '图书', 1)]
(Background on this error at: https://sqlalche.me/e/14/gkpj)
`
原因: manager.py 下的 sync_permissions 方法,没有关注代码中搜集到的权限项是否有重复,于是最终在插入lin_permission表中时,name+module 复合唯一键索引报错。
建议: 在 new_added_permissions 增加数据之前,判断一下是否已经有相同的name+module存在。 或者在new_added_permissions生成好之后,整体检查去重一次,再进行数据库同步操作