@@ -167,11 +167,16 @@ class Sample1TeamDetail2(tms.Team):
167
167
return loader.load(self .id)
168
168
```
169
169
170
+ > ` resolve_method ` 并不需要从顶层 class 就开始定义. ` Resolver ` 会递归遍历然后找到` resolver_method ` 进行解析.
171
+ >
172
+ > pydantic-resolve 不会去处理 ORM model 和 schema 直接是否统一声明的问题, 因为 ORM 层面向的持久层和pydantic schema 面向的业务层并不能保证始终一致.
173
+
174
+
170
175
## Dataloader 的使用
171
176
172
177
Dataloader 的作用收集完所有要查询的 parent_ids 之后,一次性查询到所有的 childrent 对象,接着根据 child 的 parent_id 聚合起来。
173
178
174
- 数据关系可能有 1:1, 1 : N , M : N , 从 parent 角度看的话,就会只有 1:1 和 1: N 两种。 对应这两种情况,` pydantic2-resolve ` 提供了两个辅助函数
179
+ 数据关系从 parent 角度看的话,有 1:1 和 1: N 两种。 对应这两种情况,` pydantic2-resolve ` 提供了两个辅助函数
175
180
176
181
``` python
177
182
from pydantic2_resolve import build_list, build_object
@@ -191,11 +196,11 @@ async def team_to_sprint_loader(team_ids: list[int]):
191
196
192
197
可以看到 1:1 的关系查询 id 是目标的主键, 查询非常简单, 因此可复用性最高。
193
198
194
- 而 1: N 的查询需要有对应的关系表来确定,所以复用情况受限于 parent 类型 。
199
+ 而 1: N 的查询需要有对应的关系表 (parent_id -> id) 来确定,所以复用情况取决于 parent_id 。
195
200
196
201
### 1:1
197
202
198
- 用 story 举例, ` story.owner_id ` 指定了一个 story 的负责人, 如果需要把 user 信息添加到 story, 则只需直接复用 ` user_batch_loader ` 方法。
203
+ 用 story 举例, ` story.owner_id ` 指定了一个 story 的负责人, 如果需要把 user 信息添加到 story, 则只需直接使用 ` user_batch_loader ` 方法。
199
204
200
205
``` python
201
206
class Sample1StoryDetail (ss .Story ):
@@ -208,14 +213,12 @@ class Sample1StoryDetail(ss.Story):
208
213
return loader.load(self .owner_id)
209
214
```
210
215
211
- 可以在 swagger 中查看输出。
212
-
213
216
### 1: N
214
217
215
218
以 teams 举例, team_user 表维护了 team 和 user 之间的关系。
216
219
所以我们的 loader 需要 join team_user 来查询 user.
217
220
218
- 因此这种类型的 dataloader 的复用是跟着 parent 类型走的 .
221
+ 因此这种类型的 dataloader 的复用是跟着 parent 走的 .
219
222
220
223
``` python
221
224
# team -> user query
@@ -250,6 +253,20 @@ class Sample1TeamDetail(tms.Team):
250
253
return loader.load(self .id)
251
254
```
252
255
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 的功能
254
271
255
- 至此, Dataloader 的复用性就介绍完了。
272
+ 这样一来 Resolver 就能按需来生成各个 loader 实例. 于是 loader 之间的替换修改就非常容易. 而且也不用把所有 loader 往一个 context 里面放了.
0 commit comments