过滤已评估的QuerySet

时间:2013-01-11 00:25:45

标签: django django-models

我正在评估一个QuerySet,然后是另一个,但第二个是第一个的子集。我正在尝试以有效的方式执行此操作,尽可能少的数据库调用。 (之前有人问过,但说实话,我并不完全理解答案,我不确定它们是否完全适用于我正在考虑的事情。)

在视图中使用Django doc example Weblog models,这是尝试优化之前的代码:

myblog = Blog.objects.get(pk=1)

d={} #going to pass this to my template

# not using count()
d['num_of_entries'] = len(myblog.entry_set.all()) 

# not using exists()
d['is_jolly'] = bool(Entry.objects.filter(blog=myblog, headline__startswith='Jolly'))

# ... other code but no further use of database in this view

第二个QuerySet是第一个QuerySet的子集。我是否应该尝试使用纯Python来获取子集(因此只评估一个QuerySet - 一个较少的数据库调用)?

或者,或许只是做以下事情?

# other code as above

d['num_of_entries'] = myblog.entry_set.count()

d['is_jolly'] = Entry.objects.filter(blog=myblog, headline__startswith='Jolly').exists()

# ... other code but no further use of database in this view

1 个答案:

答案 0 :(得分:5)

“尽可能少的数据库查询”不是正确的标准。您还要考虑这些数据库查询完成的工作量,以及从数据库传输到Django服务器的数据量。

让我们考虑实现你所追求的两种方式。方法1:

entries = myblog.entry_set.all()
num_of_entries = len(entries)
is_jolly = any(e.headline.startswith('Jolly') for e in entries)

方法2:

num_of_entries = myblog.entry_set.count()
is_jolly = Entry.objects.filter(blog=myblog, headline__startswith='Jolly').exists()

在方法1中,有一个数据库查询,但该查询类似于SELECT * FROM ENTRY WHERE ...。它可能会获取大量条目,并将所有内容通过网络传输到您的Django服务器,然后将几乎所有内容丢弃(实际上它唯一的字段)看看是headline字段。

在方法2中有两个数据库查询,但第一个是SELECT COUNT(*) FROM ENTRY WHERE ...,它只获取一个整数,第二个是SELECT EXISTS(...),它只获取一个布尔值。由于这些查询不必获取所有匹配的条目,因此数据库可以更多地优化查询。

因此,在这种情况下,方法2看起来要好得多,即使它会发出更多查询。