Peewee在内部连接期间返回多个对象

时间:2015-03-14 03:35:44

标签: python peewee

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

1 个答案:

答案 0 :(得分:2)

您的代码存在两个问题。

首先,即使您已加入Child,调用parent.children也会执行额外的单独查询。

由于第一个问题,你错误地认为外循环在做什么,这只是给你Parent1 + Child1,Parent1 + Child2的Parent部分。

要解决此问题,您可以使用prefetchaggregate_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