下面的代码是否会在每次调用www.example.com时查询数据库question.name?
class Question(models.Model):
name=models.CharField()
test=models.ForeignKey(Test)
questions = Question.objects.filter(test=some_test)
for question in questions:
question_name = question.name
我的视图接受一组问题和用户响应,并对工作表进行评分。我的目标是在不返回数据库的情况下执行所有评分,然后使用后台任务保存比较结果(字典),如果需要更长时间也可以。我想排除所有不必要的数据库匹配。
2条答案
按热度按时间c0vxltue1#
好吧,你的问题不清楚,但有一件事是肯定的,至少有一个命中数据库将是必需的。事实上,在代码示例中,您使用:
但是如果
question
不是Question
模型的示例,我不认为这是可行的。因此,考虑到您在创建示例的查询中对数据库的初始命中,
question_name
可以根据需要经常重用,而不必访问数据库。这是数据库中一行的静态示例。编辑
现在对于您的编辑,它不是相同的行为。为了正确理解幕后发生的事情,你需要理解“懒惰”的概念。事实上,由于Django中的查询集是懒惰的,这行:
不会在数据库里找到匹配的QuerySets代表SQL查询集。因此,在这一点上,由于您没有要求从数据库中获取某些内容,因此实际上尚未对其进行评估。这是我们想要的行为,因为它确保了数据库只在需要的时候被访问。正如文档所说,这里是查询集被评估的情况:
迭代
QuerySet是可迭代的,它在您第一次迭代它时执行其数据库查询。
切片
对一个未求值的QuerySet进行切片通常会返回另一个未求值的QuerySet,但是如果你使用切片语法的“step”参数,Django会执行数据库查询,并返回一个列表。对已计算的QuerySet进行切片也会返回一个列表。
筛选/缓存
repr()。当您对QuerySet调用repr()时,它将被计算。这在Python交互式解释器中是为了方便起见,因此当交互式使用API时,您可以立即看到结果。
len()。QuerySet在调用len()时计算。如您所料,这将返回结果列表的长度。
list()。通过调用list()强制计算QuerySet
bool()。在布尔上下文中测试QuerySet,例如使用bool()、or、and或if语句将导致执行查询
所以,正如你所看到的,情况1适用于你的特殊情况。迭代将导致数据库上的命中。
bjp0bcyl2#
很好的问题,我也一直在寻找答案。从我读到的:当你开始迭代
queryset
时,所有与queryset
匹配的行都将从数据库中获取并转换为Django模型。这被称为evaluation
(source)。一旦使用任何技术对
queryset
进行了计算-无论是迭代或强制转换为list/set
,还是在if
语句中使用它,以及here描述的其他技术,再次迭代它或使用它的属性都不会触发另一个查询/数据库命中,因为它已经被缓存了。除非-它是一个外键属性(前向或后向关系字段),在这种情况下,还可以使用select_related
或prefetch_related
来缓存这些字段,以便访问这些字段不会导致数据库命中(source)。简而言之,一旦计算了
queryset
,它的属性被检索,每个对象被缓存,用点运算符获取这些不会导致数据库命中,因为它是从该高速缓存中检索的,而不是从数据库中检索的,但是如果它s是一个外键属性,您没有按照定义缓存它,比如说使用cached_property
装饰器,或者在使用select_related
检索查询集时,或者prefetch_related
,访问该属性将导致数据库命中(部分源)。