Skip to content

Commit cb10f9a

Browse files
committed
add some thoughts
1 parent aa55b36 commit cb10f9a

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

src/router/sample_1/readme-cn.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,16 @@ class Sample1TeamDetail2(tms.Team):
167167
return loader.load(self.id)
168168
```
169169

170+
> `resolve_method` 并不需要从顶层 class 就开始定义. `Resolver` 会递归遍历然后找到`resolver_method` 进行解析.
171+
>
172+
> pydantic-resolve 不会去处理 ORM model 和 schema 直接是否统一声明的问题, 因为 ORM 层面向的持久层和pydantic schema 面向的业务层并不能保证始终一致.
173+
174+
170175
## Dataloader 的使用
171176

172177
Dataloader 的作用收集完所有要查询的 parent_ids 之后,一次性查询到所有的 childrent 对象,接着根据 child 的 parent_id 聚合起来。
173178

174-
数据关系可能有 1:1, 1:N, M:N, 从 parent 角度看的话,就会只有 1:1 和 1:N 两种。 对应这两种情况,`pydantic2-resolve` 提供了两个辅助函数
179+
数据关系从 parent 角度看的话, 1:1 和 1:N 两种。 对应这两种情况,`pydantic2-resolve` 提供了两个辅助函数
175180

176181
```python
177182
from pydantic2_resolve import build_list, build_object
@@ -191,11 +196,11 @@ async def team_to_sprint_loader(team_ids: list[int]):
191196

192197
可以看到 1:1 的关系查询 id 是目标的主键, 查询非常简单, 因此可复用性最高。
193198

194-
而 1:N 的查询需要有对应的关系表来确定,所以复用情况受限于 parent 类型
199+
而 1:N 的查询需要有对应的关系表 (parent_id -> id) 来确定,所以复用情况取决于 parent_id
195200

196201
### 1:1
197202

198-
用 story 举例, `story.owner_id` 指定了一个 story 的负责人, 如果需要把 user 信息添加到 story, 则只需直接复用 `user_batch_loader` 方法。
203+
用 story 举例, `story.owner_id` 指定了一个 story 的负责人, 如果需要把 user 信息添加到 story, 则只需直接使用 `user_batch_loader` 方法。
199204

200205
```python
201206
class Sample1StoryDetail(ss.Story):
@@ -208,14 +213,12 @@ class Sample1StoryDetail(ss.Story):
208213
return loader.load(self.owner_id)
209214
```
210215

211-
可以在 swagger 中查看输出。
212-
213216
### 1:N
214217

215218
以 teams 举例, team_user 表维护了 team 和 user 之间的关系。
216219
所以我们的 loader 需要 join team_user 来查询 user.
217220

218-
因此这种类型的 dataloader 的复用是跟着 parent 类型走的.
221+
因此这种类型的 dataloader 的复用是跟着 parent 走的.
219222

220223
```python
221224
# team -> user query
@@ -250,6 +253,20 @@ class Sample1TeamDetail(tms.Team):
250253
return loader.load(self.id)
251254
```
252255

253-
> 顺便一提, `resolve_method` 并不需要从顶层 class 就开始定义. `Resolver` 会递归遍历然后找到`resolver_method` 进行解析.
256+
至此, Dataloader 的使用就介绍玩了.
257+
258+
259+
## 其他想法
260+
261+
对于使用过 `graphene` 或者 `strawberry` 之类 graphql 框架的开发, dataloader 是一个很熟悉的东西.
262+
263+
在GraphQL 的模式下, 添加loader 需要将所有要使用的 loader 放到一个公共 context 里面, 这个问题受制于 GraphQL 单一入口, 所以没有好的解决方法.
264+
265+
- https://github.com/syrusakbary/aiodataloader?tab=readme-ov-file#creating-a-new-dataloader-per-request
266+
- https://strawberry.rocks/docs/guides/dataloaders#usage-with-context
267+
268+
这间接导致, 如果一个 loader 在多处被使用了, 那么对这个loader 的修改就会很困难. ( 因为 Query 太全能, 一个系统被全局关联了, 反而导致修改很困难 )
269+
270+
因此 `pydantic-resolve` 利用 Resolver 提供的单独入口, 实现了通过 `LoaderDepend` 就近申明 loader 的功能
254271

255-
至此, Dataloader 的复用性就介绍完了。
272+
这样一来 Resolver 就能按需来生成各个 loader 实例. 于是 loader 之间的替换修改就非常容易. 而且也不用把所有 loader 往一个 context 里面放了.

0 commit comments

Comments
 (0)