当我访问对象的属性时,Django是否会访问数据库?

时间:2017-11-10 02:04:17

标签: python django django-models

以下代码是否在每次调用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

我的观点包含一系列问题和用户回复,并在工作表中得分。我的目标是在不返回数据库的情况下执行所有评分,然后使用后台任务保存我的比较结果(字典),如果需要更长时间则可以。我想消除任何不必要的数据库命中。

1 个答案:

答案 0 :(得分:0)

嗯,你的问题不清楚,但有一点可以肯定,至少需要对数据库进行一次点击。实际上,在您的代码示例中使用:

question_name = question.name

但如果question事先不是Question型号的实例,我就不会看到这种情况。

因此,考虑到您从查询创建实例时对数据库的初始命中,question_name可以根据需要随时重复使用,而无需访问数据库。请将此视为数据库行的静态实例。

修改

现在进行编辑,这是不一样的行为。要正确理解幕后发生的事情,你需要理解"懒惰"的概念。事实上,由于查询集在Django中是懒惰的,所以这一行:

questions = Question.objects.filter(test=some_test)

不会导致数据库受到任何影响。 Querysets代表SQL查询集。因此,此时,由于您没有要求从数据库中获取某些内容,因此尚未对其进行实际评估。这是想要的行为,因为它确保仅在需要时访问数据库。正如documentation所述,这里是评估查询集的情况:

<强> 迭代

  

QuerySet是可迭代的,它首先执行其数据库查询   你迭代它的时间。

<强> 切片

  

对未评估的QuerySet进行切片通常会返回另一个未评估的QuerySet   QuerySet,但是如果你使用的话,Django会执行数据库查询   切片语法的“step”参数,并将返回一个列表。切片   已评估的QuerySet也返回一个列表。

<强> 酸洗/缓存

  

再版()。在对它调用repr()时会评估QuerySet。这是   为了方便Python交互式解释器,你可以   在交互使用API​​时立即看到您的结果。

     

LEN()。在您上面调用len()时会评估QuerySet。就像你一样   可能期望,返回结果列表的长度。

     

列表()。通过调用list()来强制评估QuerySet

     

BOOL()。在布尔上下文中测试QuerySet,例如使用bool(),   或者,或者if语句将导致查询被执行

因此,您可以看到情况1适用于您的特定情况。迭代将导致数据库命中。