在django中评估QuerySets时遇到问题

时间:2016-01-15 09:51:31

标签: django django-queryset lazy-evaluation

考虑以下示例

data = Employee.objects.all()
for i in data:
   print i.name

从我的不足之处来看,它为每个循环命中数据库。我不确定天气是对还是错。

下一个疑问是

data = Employee.objects.get(id=1)

在这种情况下何时会命中数据库?如果我将数据存储到另一个变量怎么办?

如果我做了

data = Employee.objects.all()
data1 = []
data1 = data
for i in data1:
    print i

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

2 个答案:

答案 0 :(得分:8)

  1. 在第一种情况下,在循环开始时评估查询集(因此命中数据库)once
  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'
    
  3. 如果您想获取最新保存对象的版本,可以调用refresh_from_db()方法

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

答案 1 :(得分:2)

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

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

  3.   
        
    • 第一次迭代它们
    •   
    • 当你切片时。例如:Post.objects.all()[:3]
    •   
    • 当您挑选或缓存它们时
    •   
    • 当您致电repr()len()
    • 时   
    • 当您明确呼叫list()
    • 时   
    • bool()orandif
    • 等语句中对其进行测试时   

    从书Django by Example, p. 21

    有关评估QuerySets的详细信息,请参阅docs