在django中评估QuerySets时遇到问题

Gau*_*rav 3 django lazy-evaluation django-queryset

请考虑以下示例

data = Employee.objects.all()
for i in data:
   print i.name
Run Code Online (Sandbox Code Playgroud)

从我在这里的低估,它为每个循环命中数据库.我不确定天气是对还是错.

下一个疑问是

data = Employee.objects.get(id=1)
Run Code Online (Sandbox Code Playgroud)

在这种情况下它会打到数据库吗?如果我将数据存储到另一个变量怎么办?

如果我做了

data = Employee.objects.all()
data1 = []
data1 = data
for i in data1:
    print i
Run Code Online (Sandbox Code Playgroud)

上面和这个之间有什么区别?

Ale*_*zov 8

  1. 在第一种情况下,在循环开始时评估查询集(因此命中数据库)一次.
  2. 这些get()调用将立即打到数据库.将获取所有模型数据,并且在访问模型属性时不会访问数据库(除非它们是ForeignKeys).如果已将其存储在另一个变量中,则不会以任何方式链接这些实例.例如:

    var1 = Employee.objects.get(pk=1)
    var2 = Employee.objects.get(pk=1)
    
    var1.name = 'var1'
    var2.name = 'var2'
    var2.save()
    
    print var1.name
    >>> 'var1'
    
    Run Code Online (Sandbox Code Playgroud)

如果您想获取最新保存对象的版本,可以调用该refresh_from_db()方法

    var1.refresh_from_db()
    var1.name
    >>> 'var2'
Run Code Online (Sandbox Code Playgroud)
  1. 1)和3)之间没有区别,因为在3)中你只需要通过data1变量访问查询集.它不会在赋值时进行评估,但会在迭代时进行评估.


dor*_*oru 3

  1. 在第一种情况下,它将在 for 循环开始时访问数据库,更准确地说是在第一个循环时访问数据库。

  2. 在第二种情况下,它还不会访问数据库,因为尚未评估 QuerySet。查询集是惰性的,并且在以下情况下进行评估:

  • 第一次迭代它们时
  • 当你把它们切片时。例如:Post.objects.all()[:3]
  • 当您腌制或缓存它们时
  • 当您致电repr()len()联系他们时
  • 当你明确地呼吁list()他们时
  • 当您在诸如 、 、 或 之类的语句中bool()测试orandif

摘自《Django by Example》一书,第 14 页。21

有关何时评估 QuerySet 的更多信息,请参阅文档