【问题标题】:Django, can I get reference objects included with a querysetDjango,我可以获取查询集中包含的参考对象吗
【发布时间】:2013-12-19 21:17:57
【问题描述】:

假设我有这些模型:

models.py:

class Item(models.Model):
    ref_id = models.PositiveIntegerField()
    name = models.CharacterField(max_length=32)

class ItemDue(models.Model):
    item = models.ForeignKey(Item)
    due_date = models.DateField(null=True, blank=True)
    lots of other fields below
    .
    .
    .

我想查询 ItemDue 对象,但还想在查询中包含 Item

如果我得到一组ItemDues,我可以这样循环:

for item_due in ItemDue.objects.filter(some_criteria):
    print item_due.item.ref_id

但是,当我进行一些性能测试时,这将返回数据库以获取引用的 Item 对象,因此我必须为每个 ItemDue 运行另一个查询以获取 Item.ref_id。这在一个巨大的查询中产生了影响,所以我想获得Item.ref_id 以及查询集来获得ItemDues。我可以使用.values('id', 'item__ref_id') 来获取带有iditem__ref_idItemDue 的字典。所以,我可以对ItemDue 中的所有字段使用.values('id', 'item__ref_id', ...),但这将是很多工作。有没有一种简单的方法可以附加到查询集的值以获取该引用对象,而无需拼出ItemDue 中的所有字段以及一个额外的字段item__ref_id

谢谢

编辑:

这是在 manage.py shell 中运行的一些代码:

def check():
    start = datetime.now()
    print "Starting {0}".format(datetime.now() - start)
    index = 0
    item_rows = dict()
    print "Getting Items for PG and Parents {0}".format(datetime.now() - start)

    # items due for PG
    items = pg.item_due.all().filter(disabled=False).select_related()

    # Loop the parents, and chain their items due to the PG items due.
    for p in parents:
        items = itertools.chain(items, p.item_due.all().filter(disabled=False).select_related())
        index += 1
    print "All Items Retrieved {0}".format(datetime.now() - start)
    for item in items:
        pass
    print "Loop Items Complete {0}".format(datetime.now() - start)
    return item_rows

>>> rows = check()
Starting 0:00:00.000008
Getting Items for PG and Parents 0:00:00.000032
All Items Retrieved 0:00:00.004669
Loop Items Complete 0:00:00.022597

请注意循环项目所需的时间,而 pass 大约是 0.018 秒。

现在我只需将循环中的pass 更改为item.item.ref_id,这需要更长的时间。

def check():
    start = datetime.now()
    print "Starting {0}".format(datetime.now() - start)
    index = 0
    item_rows = dict()
    print "Getting Items for PG and Parents {0}".format(datetime.now() - start)

    # items due for PG
    items = pg.item_due.all().filter(disabled=False).select_related()

    # Loop the parents, and chain their items due to the PG items due.
    for p in parents:
        items = itertools.chain(items, p.item_due.all().filter(disabled=False).select_related())
        index += 1
    print "All Items Retrieved {0}".format(datetime.now() - start)
    for item in items:
        item.item.ref_id
    print "Loop Items Complete {0}".format(datetime.now() - start)
    return item_rows

>>> rows = check()
Starting 0:00:00.000007
Getting Items for PG and Parents 0:00:00.000031
All Items Retrieved 0:00:00.004712
Loop Items Complete 0:00:00.258209

从 0.018 秒运行循环到 0.25 秒。如果 item.item.ref_id 已经从查询中获取,为什么它需要 13 倍的时间来处理它?

【问题讨论】:

  • 需要注意的是,如果我将循环 for item in items: 更改为 item.id 而不是 item.item.ref_id 它会回到快速的 0.018 秒。那么,如果获取select_related() 对象,为什么这个引用对象查找需要这么长时间?

标签: python django django-queryset


【解决方案1】:

使用select_related一次查询获取相关表数据:

for item_due in ItemDue.objects.filter(some_criteria).select_related():
    print item_due.item.ref_id

【讨论】:

  • 哇,多么简单。我只是没有正确搜索。谢谢。让我附加我的问题,因为似乎有其他东西在减慢速度。
  • @Furbeenator 您生成的查询与 p 中的父项一样多(对于父项中的 p:items = ..)。并在下一个周期中逐个执行查询以获取结果(以获取 item.item.ref_id)。直到您真正尝试获取数据 django 不执行查询...所以在这里您不执行任何数据库查询:对于项目中的项目:通过
  • Ahhhh,你的意思是因为它们是惰性查询集,它们实际上在访问之前不会从数据库中获取数据?
  • 但是为什么在循环中使用 item.id 会很快,而当我使用 item.item.ref_id 时会减慢呢?
  • 也许我还有其他事情要做,但至少我知道如何指定相关的。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 2011-09-10
  • 2013-03-07
  • 2013-09-23
  • 2014-04-04
  • 2011-07-23
  • 2011-04-11
相关资源
最近更新 更多