我有两种型号的储物柜和抽屉

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

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


目前我正在从选择查询生成json

storages = Storage.select()


结果,我得到了一个json数组,如下所示:

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


我知道,peewee允许使用storage.drawer()查询所有抽屉。但是我正在努力为每个存储都包含一个json数组,该数组包含该存储的所有抽屉。我试图使用联接

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)个查询,每个涉及的表一个(在您的情况下为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))

10-08 07:35
查看更多