我有两种型号的储物柜和抽屉
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))