在 peewee (Flask) 的查询中包含 OneToMany 关系

Include OneToMany relationship in query in peewee (Flask)

我有储物柜和抽屉两个型号

class Storage(BaseModel):
    id = PrimaryKeyField()
    name = CharField()
    description = CharField(null=True)

class Drawer(BaseModel):
    id = PrimaryKeyField()
    name = CharField()
    storage = ForeignKeyField(Storage, related_name="drawers")

目前我正在从 select 查询

生成 json
storages = Storage.select()

结果我得到了一个 json 数组,它看起来像这样:

[{
   description: null,
   id: 1,
   name: "Storage"
},
{
   description: null,
   id: 2,
   name: "Storage 2"
}]

我知道,peewee 允许使用 storage.drawer() 查询所有抽屉。但是我正在努力将 json 数组包含到包含该存储的所有抽屉的每个存储中。我尝试使用 join

storages = Storage.select(Storage, Drawer)
                  .join(Drawer)
                  .where(Drawer.storage == Storage.id)
                  .group_by(Storage.id)

但我只是取回了第二个带抽屉的储物柜,但不包括抽屉阵列。这甚至可以通过连接实现吗?或者我是否需要遍历每个存储检索抽屉并将它们附加到存储?

这是 ORM 的经典 O(n) 查询问题。文档 goes into some detail on various ways to approach the problem.

对于这种情况,您可能需要 prefetch()。它将执行 O(k) 个查询,而不是 O(n) 个查询,每个 table 个查询(在你的情况下是 2 个)。

storages = Storage.select().order_by(Storage.name)
drawers = Drawer.select().order_by(Drawer.name)
query = prefetch(storages, drawers)

为了对此进行序列化,我们将遍历 prefetch 返回的 Storage 对象。关联的抽屉将使用 Drawer.storage 外键的 related_name + '_prefetch' (drawers_prefetch):

预填充
accum = []
for storage in query:
    data = {'name': storage.name, 'description': storage.description}
    data['drawers'] = [{'name': drawer.name}
                       for drawer in storage.drawers_prefetch]
    accum.append(data)

要使这个更容易,您可以使用 playhouse.shortcuts.model_to_dict 助手:

accum = []
for storage in query:
    accum.append(model_to_dict(storage, backrefs=True, recurse=True))