From 4b597da1e72dbfd148c4e3efe962de481a52e70b Mon Sep 17 00:00:00 2001 From: Wu Clan Date: Sun, 10 Nov 2024 00:33:45 +0800 Subject: [PATCH] Add the flush usage --- docs/advanced/filter.md | 4 ++-- docs/advanced/flush.md | 11 ++++++++++ docs/usage/create_model.md | 4 +++- docs/usage/create_models.md | 3 ++- docs/usage/delete_model.md | 5 +++-- docs/usage/delete_model_by_column.md | 3 ++- docs/usage/select_model.md | 2 +- docs/usage/update_model.md | 6 +++--- docs/usage/update_model_by_column.md | 3 ++- mkdocs.yml | 1 + sqlalchemy_crud_plus/crud.py | 30 +++++++++++++++++++++++++--- 11 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 docs/advanced/flush.md diff --git a/docs/advanced/filter.md b/docs/advanced/filter.md index 0e29efe..6e0c790 100644 --- a/docs/advanced/filter.md +++ b/docs/advanced/filter.md @@ -116,7 +116,7 @@ items = await item_crud.select_models( `or` 过滤器的高级用法,每个键都应是库已支持的过滤器,仅允许字典 ```python title="__mor" -# 获取年龄等于 30 岁和 40 岁的员工 +# 获取年龄等于 30 岁或 40 岁的员工 items = await item_crud.select_models( session=db, age__mor={'eq': [30, 40]}, # (1) @@ -133,7 +133,7 @@ items = await item_crud.select_models( `or` 过滤器的更高级用法,每个值都应是一个已受支持的条件过滤器,它应该是一个数组 ```python title="__gor__" -# 获取年龄在 30 - 40 岁之间且薪资大于 20k 的员工 +# 获取年龄在 30 - 40 岁之间或薪资大于 20k 的员工 items = await item_crud.select_models( session=db, __gor__=[ diff --git a/docs/advanced/flush.md b/docs/advanced/flush.md new file mode 100644 index 0000000..549081d --- /dev/null +++ b/docs/advanced/flush.md @@ -0,0 +1,11 @@ +## `flush()` + +- `flush` 是将更改从 Python 移动到数据库的事务缓冲区 +- 它会生成必要的 SQL 语句并发送到数据库执行,但不会提交(commit)事务 +- 在 `flush` 之后,数据会被写入数据库,但事务依然是活跃的(未提交),除非发生错误,在这种情况下,整个事务将回滚,`flush` + 的更改也会被撤销 + +!!! tip "提示" + + 如果你在事务提交前无需对新实例进行某些操作,`flush` 是没必要的,在 `commit` 时,SQLAlchemy 会隐式地调用一次 `flush`, + 确保所有挂起的更改都被同步到数据库,然后提交事务 diff --git a/docs/usage/create_model.md b/docs/usage/create_model.md index 4576e89..bf08407 100644 --- a/docs/usage/create_model.md +++ b/docs/usage/create_model.md @@ -3,12 +3,14 @@ async def create_model( self, session: AsyncSession, obj: CreateSchema, + flush: bool = False, commit: bool = False, **kwargs, ) -> Model: ```` -此方法提供 `commit` 参数,详见:[提交](../advanced/commit.md) +- 此方法提供 `flush` 参数,详见:[冲洗](../advanced/flush.md) +- 此方法提供 `commit` 参数,详见:[提交](../advanced/commit.md) !!! note "关键字参数" diff --git a/docs/usage/create_models.md b/docs/usage/create_models.md index 5dc37a4..90fd7d2 100644 --- a/docs/usage/create_models.md +++ b/docs/usage/create_models.md @@ -3,13 +3,14 @@ async def create_models( self, session: AsyncSession, objs: Iterable[CreateSchema], + flush: bool = False, commit: bool = False, **kwargs, ) -> list[Model]: ``` +- 此方法提供 `flush` 参数,详见:[冲洗](../advanced/flush.md) - 此方法提供 `commit` 参数,详见:[提交](../advanced/commit.md) - - 此方法还提供与 `create_model()` 相同用法的关键字参数,需要额外注意的是,`create_models()` 会将关键字参数写入每个实例中 ## 示例 diff --git a/docs/usage/delete_model.md b/docs/usage/delete_model.md index b169bd7..e742dbf 100644 --- a/docs/usage/delete_model.md +++ b/docs/usage/delete_model.md @@ -3,12 +3,13 @@ async def delete_model( self, session: AsyncSession, pk: int, + flush: bool = False, commit: bool = False, ) -> int: ``` -- 此方法使用主键 pk 参数,详见:[主键](../advanced/primary_key.md) - +- 此方法提供 `flush` 参数,详见:[冲洗](../advanced/flush.md) +- 此方法使用主键 `pk` 参数,详见:[主键](../advanced/primary_key.md) - 此方法提供 `commit` 参数,详见:[提交](../advanced/commit.md) ## 示例 diff --git a/docs/usage/delete_model_by_column.md b/docs/usage/delete_model_by_column.md index 796276c..32155a0 100644 --- a/docs/usage/delete_model_by_column.md +++ b/docs/usage/delete_model_by_column.md @@ -5,13 +5,14 @@ async def delete_model_by_column( allow_multiple: bool = False, logical_deletion: bool = False, deleted_flag_column: str = 'del_flag', + flush: bool = False, commit: bool = False, **kwargs, ) -> int: ``` +- 此方法提供 `flush` 参数,详见:[冲洗](../advanced/flush.md) - 此方法提供 `commit` 参数,详见:[提交](../advanced/commit.md) - - 此方法可结合 [高级过滤器](../advanced/filter.md) 使用 ## 删除多条 diff --git a/docs/usage/select_model.md b/docs/usage/select_model.md index c44b14a..e601325 100644 --- a/docs/usage/select_model.md +++ b/docs/usage/select_model.md @@ -2,7 +2,7 @@ async def select_model(self, session: AsyncSession, pk: int) -> Model | None: ``` -此方法使用主键 pk 参数,详见:[主键](../advanced/primary_key.md) +此方法使用主键 `pk` 参数,详见:[主键](../advanced/primary_key.md) ## 示例 diff --git a/docs/usage/update_model.md b/docs/usage/update_model.md index 76877f6..ae5416b 100644 --- a/docs/usage/update_model.md +++ b/docs/usage/update_model.md @@ -4,15 +4,15 @@ async def update_model( session: AsyncSession, pk: int, obj: UpdateSchema | dict[str, Any], + flush: bool = False, commit: bool = False, **kwargs, ) -> int: ``` -- 此方法使用主键 pk 参数,详见:[主键](../advanced/primary_key.md) - +- 此方法提供 `flush` 参数,详见:[冲洗](../advanced/flush.md) +- 此方法使用主键 `pk` 参数,详见:[主键](../advanced/primary_key.md) - 此方法提供 `commit` 参数,详见:[提交](../advanced/commit.md) - - 此方法还提供与 `create_model()` 相同用法的关键字参数 ## 示例 diff --git a/docs/usage/update_model_by_column.md b/docs/usage/update_model_by_column.md index 2a011e6..d39c221 100644 --- a/docs/usage/update_model_by_column.md +++ b/docs/usage/update_model_by_column.md @@ -4,13 +4,14 @@ async def update_model_by_column( session: AsyncSession, obj: UpdateSchema | dict[str, Any], allow_multiple: bool = False, + flush: bool = False, commit: bool = False, **kwargs, ) -> int: ``` +- 此方法提供 `flush` 参数,详见:[冲洗](../advanced/flush.md) - 此方法提供 `commit` 参数,详见:[提交](../advanced/commit.md) - - 此方法可结合 [高级过滤器](../advanced/filter.md) 使用 ## 更新多条 diff --git a/mkdocs.yml b/mkdocs.yml index 8e4d9ae..01dfb9e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -27,6 +27,7 @@ nav: - 高级用法: usage/delete_model_by_column.md - Advanced: - 主键: advanced/primary_key.md + - 冲洗: advanced/flush.md - 提交: advanced/commit.md - 条件过滤: advanced/filter.md - Changelog: changelog.md diff --git a/sqlalchemy_crud_plus/crud.py b/sqlalchemy_crud_plus/crud.py index 22aeacb..ee0f69c 100644 --- a/sqlalchemy_crud_plus/crud.py +++ b/sqlalchemy_crud_plus/crud.py @@ -30,6 +30,7 @@ async def create_model( self, session: AsyncSession, obj: CreateSchema, + flush: bool = False, commit: bool = False, **kwargs, ) -> Model: @@ -38,6 +39,7 @@ async def create_model( :param session: The SQLAlchemy async session. :param obj: The Pydantic schema containing data to be saved. + :param flush: If `True`, flush all object changes to the database. Default is `False`. :param commit: If `True`, commits the transaction immediately. Default is `False`. :param kwargs: Additional model data not included in the pydantic schema. :return: @@ -47,6 +49,8 @@ async def create_model( else: ins = self.model(**obj.model_dump(), **kwargs) session.add(ins) + if flush: + await session.flush() if commit: await session.commit() return ins @@ -55,6 +59,7 @@ async def create_models( self, session: AsyncSession, objs: Iterable[CreateSchema], + flush: bool = False, commit: bool = False, **kwargs, ) -> list[Model]: @@ -63,6 +68,7 @@ async def create_models( :param session: The SQLAlchemy async session. :param objs: The Pydantic schema list containing data to be saved. + :param flush: If `True`, flush all object changes to the database. Default is `False`. :param commit: If `True`, commits the transaction immediately. Default is `False`. :param kwargs: Additional model data not included in the pydantic schema. :return: @@ -75,6 +81,8 @@ async def create_models( ins = self.model(**obj.model_dump(), **kwargs) ins_list.append(ins) session.add_all(ins_list) + if flush: + await session.flush() if commit: await session.commit() return ins_list @@ -169,6 +177,7 @@ async def update_model( session: AsyncSession, pk: int, obj: UpdateSchema | dict[str, Any], + flush: bool = False, commit: bool = False, **kwargs, ) -> int: @@ -178,6 +187,7 @@ async def update_model( :param session: The SQLAlchemy async session. :param pk: The database primary key value. :param obj: A pydantic schema or dictionary containing the update data + :param flush: If `True`, flush all object changes to the database. Default is `False`. :param commit: If `True`, commits the transaction immediately. Default is `False`. :return: """ @@ -189,6 +199,8 @@ async def update_model( instance_data.update(kwargs) stmt = update(self.model).where(self.primary_key == pk).values(**instance_data) result = await session.execute(stmt) + if flush: + await session.flush() if commit: await session.commit() return result.rowcount # type: ignore @@ -198,6 +210,7 @@ async def update_model_by_column( session: AsyncSession, obj: UpdateSchema | dict[str, Any], allow_multiple: bool = False, + flush: bool = False, commit: bool = False, **kwargs, ) -> int: @@ -207,6 +220,7 @@ async def update_model_by_column( :param session: The SQLAlchemy async session. :param obj: A pydantic schema or dictionary containing the update data :param allow_multiple: If `True`, allows updating multiple records that match the filters. + :param flush: If `True`, flush all object changes to the database. Default is `False`. :param commit: If `True`, commits the transaction immediately. Default is `False`. :param kwargs: Query expressions. :return: @@ -221,6 +235,8 @@ async def update_model_by_column( instance_data = obj.model_dump(exclude_unset=True) stmt = update(self.model).where(*filters).values(**instance_data) # type: ignore result = await session.execute(stmt) + if flush: + await session.flush() if commit: await session.commit() return result.rowcount # type: ignore @@ -229,6 +245,7 @@ async def delete_model( self, session: AsyncSession, pk: int, + flush: bool = False, commit: bool = False, ) -> int: """ @@ -236,11 +253,14 @@ async def delete_model( :param session: The SQLAlchemy async session. :param pk: The database primary key value. + :param flush: If `True`, flush all object changes to the database. Default is `False`. :param commit: If `True`, commits the transaction immediately. Default is `False`. :return: """ stmt = delete(self.model).where(self.primary_key == pk) result = await session.execute(stmt) + if flush: + await session.flush() if commit: await session.commit() return result.rowcount # type: ignore @@ -251,18 +271,20 @@ async def delete_model_by_column( allow_multiple: bool = False, logical_deletion: bool = False, deleted_flag_column: str = 'del_flag', + flush: bool = False, commit: bool = False, **kwargs, ) -> int: """ - Delete + Delete an instance by model column :param session: The SQLAlchemy async session. - :param commit: If `True`, commits the transaction immediately. Default is `False`. - :param kwargs: Query expressions. :param allow_multiple: If `True`, allows deleting multiple records that match the filters. :param logical_deletion: If `True`, enable logical deletion instead of physical deletion :param deleted_flag_column: Specify the flag column for logical deletion + :param flush: If `True`, flush all object changes to the database. Default is `False`. + :param commit: If `True`, commits the transaction immediately. Default is `False`. + :param kwargs: Query expressions. :return: """ filters = parse_filters(self.model, **kwargs) @@ -275,6 +297,8 @@ async def delete_model_by_column( else: stmt = delete(self.model).where(*filters) result = await session.execute(stmt) + if flush: + await session.flush() if commit: await session.commit() return result.rowcount # type: ignore