class Parent(BaseModel):
name = peewee.CharField()
class Child(BaseModel):
name = peewee.CharField()
parent = peewee.ForeignKeyField(Parent, related_name='children')
parent = Parent.create(name="Parent1")
child1 = Child.create(name="Child1", parent=parent)
chilld2 = Child.create(name="Child2", parent=parent)
query = (Parent.select()
.join(Child))
for p in query:
print p.name
for c in p.children:
print "\t",c.name
这导致以下输出:
Parent1
Child1
Child2
Parent1
Child1
Child2
我原本应该这样做:
Parent1
Child1
Child2
似乎我在迭代SQL结果集而不是ORM意义上的对象。鉴于从ORM角度来看,只有一个“父对象”,在查询中,如何修改查询或迭代查询以获得预期结果?
我想将查询返回到我的模板,就像在peewee示例应用程序中一样,只是迭代它以显示对象,但如果我这样做,它将显示相同的对象两次(或n次为n个相关的子项) )。
我知道我可以做到以下几点:
p = query.get()
print p.name
for c in p.children:
print "\t", c.name
但是当我有多个父母并且只是想要遍历它们时,我无法确定有多少父母。 count
查询方法返回结果集的计数,而不是它们的父对象数的计数。
这也是一个解决方法:
pars = []
for p in query:
if p not in pars:
pars.append(p)
for p in pars:
print p.name
for c in p.children:
print "\t", c.name
答案 0 :(得分:2)
您的代码存在两个问题。
首先,即使您已加入Child
,调用parent.children
也会执行额外的单独查询。
由于第一个问题,你错误地认为外循环在做什么,这只是给你Parent1 + Child1,Parent1 + Child2的Parent部分。
要解决此问题,您可以使用prefetch
或aggregate_rows
:
# Execute a single query and de-dupe the duplicated parent rows.
query = Parent.select(Parent, Child).join(Child).aggregate_rows()
for parent in query:
print parent.name
for child in parent.children:
print childname
# Execute a query for each joined table. Generally more efficient
# than aggregate_rows().
query = prefetch(Parent.select(), Child)
for parent in query:
print parent.name
for child in parent.children_prefetch: # NOTE the `_prefetch`
print child.name
这是广泛记录的:http://docs.peewee-orm.com/en/latest/peewee/querying.html#avoiding-n-1-queries