【发布时间】: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') 来获取带有id 和item__ref_id 的ItemDue 的字典。所以,我可以对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