TaleLin / lin-cms-flask

🎀A simple and practical CMS implememted by Flask
http://doc.cms.talelin.com/
Other
832 stars 216 forks source link

当代码中有相同的权限项,会导致flask db init报错的问题 #216

Closed polo2013 closed 2 years ago

polo2013 commented 2 years ago

问题复现: 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) `

原因: manager.py 下的 sync_permissions 方法,没有关注代码中搜集到的权限项是否有重复,于是最终在插入lin_permission表中时,name+module 复合唯一键索引报错。

建议: 在 new_added_permissions 增加数据之前,判断一下是否已经有相同的name+module存在。 或者在new_added_permissions生成好之后,整体检查去重一次,再进行数据库同步操作

sunlin92 commented 2 years ago

感谢反馈!问题修复已合并到master