diff --git a/README.md b/README.md index 071d693..be3a494 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,20 @@ ## Download +### pip + ```shell pip install sqlalchemy-crud-plus ``` +### uv + +```shell +uv pip install sqlalchemy-crud-plus +# 或 +uv add sqlalchemy-crud-plus +``` + ## 文档 [SQLAlchemy CRUD Plus](https://fastapi-practices.github.io/sqlalchemy-crud-plus) @@ -18,4 +28,4 @@ pip install sqlalchemy-crud-plus ## 赞助 -如果此项目能够帮助到你,你可以赞助作者一些咖啡豆表示鼓励:[:coffee: Sponsor :coffee:](https://wu-clan.github.io/sponsor/) +如果这个项目对你有帮助,欢迎[请作者喝杯咖啡](https://wu-clan.github.io/sponsor/) ☕ diff --git a/docs/advanced/filter.md b/docs/advanced/filter.md index 527e272..2c7a007 100644 --- a/docs/advanced/filter.md +++ b/docs/advanced/filter.md @@ -219,7 +219,7 @@ class UserRole(Base): ```python # 创建 -user_role_data = {"user_id": 1, "role_id": 2} +user_role_data = UserRoleCreate(user_id=1, role_id=2) user_role = await user_role_crud.create_model(session, user_role_data) # 查询(使用元组) @@ -283,8 +283,3 @@ recent_users = await user_crud.select_models( 3. **性能考虑**: 为常用过滤字段创建数据库索引 4. **OR 查询**: 过多 OR 条件可能影响性能,合理使用 5. **通配符**: 避免以通配符开头的 LIKE 查询 - -## 下一步 - -- [关系查询](relationship.md) - 学习表关系处理 -- [事务控制](transaction.md) - 掌握事务管理 diff --git a/docs/advanced/relationship.md b/docs/advanced/relationship.md index d0bd6bc..09cbd09 100644 --- a/docs/advanced/relationship.md +++ b/docs/advanced/relationship.md @@ -4,9 +4,9 @@ SQLAlchemy CRUD Plus 提供强大的关系查询功能,支持 ORM 关系预加 ## 核心参数 -- **load_strategies** - 关系数据预加载策略(需要 ORM relationship) -- **join_conditions** - JOIN 条件控制(支持有无 relationship) -- **load_options** - 原生 SQLAlchemy 选项 +- `load_strategies` - 关系数据预加载策略(需要 ORM relationship) +- `join_conditions` - JOIN 条件控制(支持有无 relationship) +- `load_options` - 原生 SQLAlchemy 选项 ## ORM 关系(有 relationship) @@ -32,7 +32,7 @@ class Post(Base): author: Mapped['User'] = relationship(back_populates='posts') ``` -**查询示例**: +查询示例: ```python # 预加载关系数据 @@ -70,7 +70,7 @@ class Post(Base): author_email: Mapped[str] = mapped_column(String(100), index=True) ``` -**查询示例**: +查询示例: ```python from sqlalchemy_crud_plus import JoinConfig @@ -139,7 +139,7 @@ result = await user_crud.select_models( #### join_on 参数 -**join_on** 定义表之间的关联条件,支持: +`join_on` 定义表之间的关联条件,支持: 1. 简单等值条件 ```python @@ -271,7 +271,7 @@ for result in results: print(f"{user.name}: {post.title if post else 'No post'}") ``` -**多表关联**: +多表关联: ```python # 关联多个表,都包含在结果中 @@ -298,7 +298,7 @@ for post, user, category in results: print(f"{post.title} by {user.name} in {category.name if category else 'Uncategorized'}") ``` -**fill_result 默认行为**: +fill_result 默认行为: ```python # fill_result=False (默认) - 只返回主表数据 @@ -316,11 +316,11 @@ users = await user_crud.select_models( # users 只包含 User 实例 ``` -**选择正确的使用方式**: +选择正确的使用方式: -- **只需要主表数据**:使用 `fill_result=False` (默认) -- **需要关联表数据**:使用 `fill_result=True` -- **复杂查询/自定义字段**:使用原生 `select()` +- 只需要主表数据:使用 `fill_result=False` (默认) +- 需要关联表数据:使用 `fill_result=True` +- 复杂查询/自定义字段:使用原生 `select()` ### JOIN 类型说明 @@ -328,7 +328,7 @@ users = await user_crud.select_models( |---------|-----------------|----------------| | `inner` | INNER JOIN | 只返回两表都匹配的记录 | | `left` | LEFT JOIN | 返回左表所有记录,右表可为空 | -| `outer` | FULL OUTER JOIN | 返回两表所有记录 | +| `full` | FULL OUTER JOIN | 返回两表所有记录 | ## load_strategies @@ -509,25 +509,25 @@ users = await user_crud.select_models( ## 最佳实践 -1. **根据场景选择方式** +1. 根据场景选择方式 - 有外键 + 标准关系 → 使用 `load_strategies` - 无外键或复杂条件 → 使用 `JoinConfig` -2. **关联查询获取多表数据** +2. 关联查询获取多表数据 - 使用原生 `select(Model1, Model2).join()` 获取多表数据 - 构建字典结果用于 API 返回 - `JoinConfig` 主要用于过滤,不直接返回关联表数据 -3. **性能优化** +3. 性能优化 - 为关联字段添加索引 - 预加载避免 N+1 查询 - 合理选择 JOIN 类型 -4. **字段命名** +4. 字段命名 - 主键关联:`user_id`(整数) - 业务字段关联:`user_email`、`customer_code`(语义化) -5. **错误处理** +5. 错误处理 - 检查关联字段是否有索引 - 验证 JOIN 条件的正确性 - 处理关联数据为空的情况 diff --git a/docs/advanced/transaction.md b/docs/advanced/transaction.md index c758b33..251c895 100644 --- a/docs/advanced/transaction.md +++ b/docs/advanced/transaction.md @@ -12,7 +12,7 @@ async with async_session.begin() as session: # 在这个块中的所有操作都在同一个事务中 user_data = UserCreate(name="张三", email="zhangsan@example.com") user = await user_crud.create_model(session, user_data) - + # 如果没有异常,事务会自动提交 # 如果有异常,事务会自动回滚 ``` @@ -24,13 +24,13 @@ async with async_session() as session: try: # 开始事务 await session.begin() - + user_data = UserCreate(name="李四", email="lisi@example.com") user = await user_crud.create_model(session, user_data) - + # 手动提交 await session.commit() - + except Exception as e: # 手动回滚 await session.rollback() @@ -48,15 +48,16 @@ async with async_session.begin() as session: # 创建用户并立即获取主键 user_data = UserCreate(name="张三", email="zhangsan@example.com") user = await user_crud.create_model(session, user_data, flush=True) - + # 此时 user.id 已可用,可用于关联操作 profile_data = ProfileCreate(user_id=user.id, bio="用户简介") profile = await profile_crud.create_model(session, profile_data) - + # 事务在 with 块结束时自动提交 ``` **使用场景:** + - 需要获取自动生成的主键 - 在同一事务中创建关联记录 - 确保数据一致性检查 @@ -76,6 +77,7 @@ await user_crud.delete_model(session, pk=1, commit=True) ``` **使用场景:** + - 独立的单个操作 - 不需要与其他操作组合 - 简化代码结构 @@ -89,11 +91,11 @@ async with async_session.begin() as session: # 创建用户(使用 flush 获取主键) user_data = UserCreate(name="王五", email="wangwu@example.com") user = await user_crud.create_model(session, user_data, flush=True) - + # 创建个人资料(使用获取到的用户主键) profile_data = ProfileCreate(user_id=user.id, bio="个人简介") profile = await profile_crud.create_model(session, profile_data) - + # 创建文章 post_data = PostCreate( title="我的第一篇文章", @@ -101,7 +103,7 @@ async with async_session.begin() as session: author_id=user.id ) post = await post_crud.create_model(session, post_data) - + # 所有操作要么全部成功,要么全部回滚 ``` @@ -113,7 +115,7 @@ async with async_session.begin() as session: existing_user = await user_crud.select_model_by_column( session, email="test@example.com" ) - + if existing_user: # 更新现有用户 user_update = UserUpdate(last_login=datetime.now()) @@ -128,7 +130,7 @@ async with async_session.begin() as session: email="test@example.com" ) user = await user_crud.create_model(session, user_data) - + return user ``` @@ -139,23 +141,23 @@ async with async_session.begin() as session: # 主事务 user_data = UserCreate(name="主用户", email="main@example.com") user = await user_crud.create_model(session, user_data, flush=True) - + # 创建保存点 savepoint = await session.begin_nested() - + try: # 嵌套事务 profile_data = ProfileCreate(user_id=user.id, bio="可能失败的操作") profile = await profile_crud.create_model(session, profile_data) - + # 提交保存点 await savepoint.commit() - + except Exception as e: # 回滚到保存点 await savepoint.rollback() print(f"嵌套事务失败,已回滚: {e}") - + # 主事务继续 return user ``` @@ -167,10 +169,10 @@ async with async_session.begin() as session: ```python async def batch_create_users(users_data: list, batch_size: int = 100): """分批处理大量数据,避免长事务""" - + for i in range(0, len(users_data), batch_size): batch = users_data[i:i + batch_size] - + async with async_session.begin() as session: # 处理一批数据 await user_crud.create_models(session, batch) @@ -187,7 +189,7 @@ async with async_session.begin() as session: for i in range(100) ] users = await user_crud.create_models(session, users_data) - + # 批量更新 await user_crud.update_model_by_column( session, @@ -202,9 +204,9 @@ async with async_session.begin() as session: ```python async def register_user( - session: AsyncSession, - user_data: UserCreate, - profile_data: ProfileCreate = None + session: AsyncSession, + user_data: UserCreate, + profile_data: ProfileCreate = None ): """用户注册,包含用户和资料创建""" async with session.begin(): @@ -212,15 +214,15 @@ async def register_user( existing = await user_crud.exists(session, email=user_data.email) if existing: raise ValueError("邮箱已存在") - + # 创建用户 user = await user_crud.create_model(session, user_data, flush=True) - + # 创建用户资料(可选) if profile_data: profile_data.user_id = user.id await profile_crud.create_model(session, profile_data) - + return user ``` @@ -228,20 +230,20 @@ async def register_user( ```python async def process_order( - session: AsyncSession, - order_data: OrderCreate, - order_items: list[OrderItemCreate] + session: AsyncSession, + order_data: OrderCreate, + order_items: list[OrderItemCreate] ): """处理订单和订单项""" async with session.begin(): # 创建订单 order = await order_crud.create_model(session, order_data, flush=True) - + # 创建订单项 for item_data in order_items: item_data.order_id = order.id await order_item_crud.create_model(session, item_data) - + # 更新库存 for item_data in order_items: await product_crud.update_model_by_column( @@ -249,7 +251,7 @@ async def process_order( obj={"stock": Product.stock - item_data.quantity}, id=item_data.product_id ) - + return order ``` @@ -264,17 +266,17 @@ async def safe_user_operation(session: AsyncSession, user_data: dict): try: # 执行操作 user = await user_crud.create_model(session, user_data) - + # 可能失败的操作 await send_welcome_email(user.email) - + return user - + except EmailError: # 特定异常处理 print("邮件发送失败,但用户创建成功") return user - + except Exception as e: # 其他异常会自动回滚事务 print(f"操作失败: {e}") @@ -287,45 +289,45 @@ async def safe_user_operation(session: AsyncSession, user_data: dict): async def bulk_process_with_savepoints(session: AsyncSession, items: list): """批量处理,部分失败不影响其他""" results = [] - + async with session.begin(): for item in items: savepoint = await session.begin_nested() - + try: result = await process_single_item(session, item) await savepoint.commit() results.append(result) - + except Exception as e: await savepoint.rollback() print(f"项目 {item.id} 处理失败: {e}") results.append(None) - + return results ``` ## 最佳实践 1. **优先使用自动事务管理** - - 使用 `async with session.begin()` 模式 - - 让异常自然传播以触发回滚 - - 避免手动管理事务状态 + - 使用 `async with session.begin()` 模式 + - 让异常自然传播以触发回滚 + - 避免手动管理事务状态 2. **合理使用 flush 和 commit** - - 需要主键时使用 `flush=True` - - 独立操作时使用 `commit=True` - - 避免在事务块中使用 `commit=True` + - 需要主键时使用 `flush=True` + - 独立操作时使用 `commit=True` + - 避免在事务块中使用 `commit=True` 3. **控制事务范围** - - 保持事务尽可能短小 - - 避免在事务中执行耗时操作 - - 考虑使用分批处理 + - 保持事务尽可能短小 + - 避免在事务中执行耗时操作 + - 考虑使用分批处理 4. **错误处理** - - 在事务外部处理业务逻辑错误 - - 使用保存点处理部分失败场景 - - 记录事务失败的详细信息 + - 在事务外部处理业务逻辑错误 + - 使用保存点处理部分失败场景 + - 记录事务失败的详细信息 ## 注意事项 @@ -333,9 +335,3 @@ async def bulk_process_with_savepoints(session: AsyncSession, items: list): 2. **事务嵌套**: 合理使用保存点,避免过深嵌套 3. **长事务**: 避免长时间持有事务,影响数据库性能 4. **异常处理**: 确保异常能够正确触发事务回滚 - -## 下一步 - -- [关系查询](relationship.md) - 学习关系查询和 JOIN -- [过滤条件](filter.md) - 高级过滤技术 -- [API 参考](../api/crud-plus.md) - 完整 API 文档 diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index b8070cc..0a23d4c 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -2,12 +2,6 @@ 本指南帮助您在 5 分钟内快速上手 SQLAlchemy CRUD Plus。 -## 安装 - -```bash -pip install sqlalchemy-crud-plus -``` - ## 基础配置 ### 数据库配置 @@ -90,6 +84,10 @@ class PostCreate(BaseModel): ## 基本使用 +!!! note "关于代码示例" +以下示例代码片段假设您已经配置好数据库连接和模型定义(参见上方"基础配置"部分),并且在异步函数中使用 `session` +对象。完整的可运行示例请参见本页底部的"完整示例"部分。 + ### 创建 CRUD 实例 ```python @@ -180,7 +178,7 @@ await user_crud.delete_model_by_column( logical_deletion=True, deleted_flag_column='is_deleted', allow_multiple=False, - pk=1 + id=1 ) ``` @@ -303,6 +301,11 @@ class UserCreate(BaseModel): email: str +class UserUpdate(BaseModel): + name: str | None = None + email: str | None = None + + class PostCreate(BaseModel): title: str content: str @@ -356,25 +359,11 @@ async def main(): await session.commit() print("更新用户名") - # 逻辑删除文章 - await post_crud.delete_model_by_column( - session, - logical_deletion=True, - deleted_flag_column='deleted_at', - allow_multiple=False, - id=post.id, - commit=True - ) - print("逻辑删除文章") + # 删除文章 + await post_crud.delete_model(session, pk=post.id, commit=True) + print("删除文章") if __name__ == "__main__": asyncio.run(main()) ``` - -## 下一步 - -- [基础用法](../usage/crud.md) - 详细的 CRUD 操作 -- [过滤条件](../advanced/filter.md) - 过滤操作符详解 -- [关系查询](../advanced/relationship.md) - 关系查询详解 -- [事务控制](../advanced/transaction.md) - 事务管理 diff --git a/docs/index.md b/docs/index.md index dc290b7..25aa7f2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,9 +15,23 @@ ### 安装 -```bash -pip install sqlalchemy-crud-plus -``` +=== "pip" + + ```bash + pip install sqlalchemy-crud-plus + ``` + +=== "uv" + + ```bash + uv pip install sqlalchemy-crud-plus + ``` + + 或者添加到项目依赖: + + ```bash + uv add sqlalchemy-crud-plus + ``` ### 基本用法 diff --git a/docs/installing.md b/docs/installing.md index 5b9d78e..943b4db 100644 --- a/docs/installing.md +++ b/docs/installing.md @@ -8,21 +8,24 @@ ## 安装 -```bash -pip install sqlalchemy-crud-plus -``` +=== "pip" -### 版本兼容性 + ```bash + pip install sqlalchemy-crud-plus + ``` -确保 SQLAlchemy 版本为 2.0+: +=== "uv" -```bash -pip install --upgrade sqlalchemy>=2.0.0 -``` + [uv](https://github.com/astral-sh/uv) 是一个极快的 Python 包管理器,推荐使用。 -## 下一步 + 安装包: -安装完成后,查看: + ```bash + uv pip install sqlalchemy-crud-plus + ``` -- [快速开始](getting-started/quick-start.md) - 5分钟上手指南 -- [基础用法](usage/crud.md) - CRUD 操作详解 + 或者添加到项目依赖: + + ```bash + uv add sqlalchemy-crud-plus + ``` diff --git a/docs/usage/crud.md b/docs/usage/crud.md index 9531a1e..4f2abd6 100644 --- a/docs/usage/crud.md +++ b/docs/usage/crud.md @@ -11,8 +11,8 @@ SQLAlchemy CRUD Plus 提供完整的 CRUD(创建、读取、更新、删除) user_data = UserCreate(name="张三", email="zhangsan@example.com") user = await user_crud.create_model(session, user_data) -# 使用字典 -user = await user_crud.create_model(session, {"name": "李四", "email": "lisi@example.com"}) +# 使用 kwargs 传递额外数据 +user = await user_crud.create_model(session, user_data, is_verified=True) # 立即提交 user = await user_crud.create_model(session, user_data, commit=True) @@ -335,9 +335,3 @@ async def batch_update_same_data(session: AsyncSession, update_data: dict, **fil 4. **复合主键**: 使用元组格式,如 `pk=(1, 2)` 5. **错误处理**: 查询不存在的记录返回 `None`,删除不存在的记录返回 `0` 6. **批量操作**: 大量数据操作时优先使用 `bulk_*` 方法 - -## 下一步 - -- [过滤条件](../advanced/filter.md) - 学习过滤操作符 -- [关系查询](../advanced/relationship.md) - 处理表关系 -- [事务控制](../advanced/transaction.md) - 深入事务管理