为什么django querysey索引操作符返回该对象的副本

时间:2013-10-04 16:21:48

标签: python django django-queryset

我知道django querysey是一个生成器而不是列表。

my_items = Item.objects.filter(id = 1)
my_items[0].name = 'joe'
my_items[0].save()

在示例中,my_items [0]是对象的副本,因此保存不会修改对象 虽然这会起作用(不会创建副本)

my_items = Item.objects.filter(id = 1)
my_item = my_items[0]
my_item.name = 'joe'
my_item.save()

在django docs(或其他任何地方)中解释这种行为的地方? 为什么他们选择返回对象的副本而不是对象本身?

2 个答案:

答案 0 :(得分:4)

记录在the section about querysets and caching中。它不仅仅是现有对象的副本。每次执行此操作时,Django都会对数据库进行单独查询,并根据响应创建新对象。以下是文档提供的示例:

>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again

但是,如果已经评估了您的查询集,则使用索引运算符获取对象将不会访问数据库,并且每次都会获得相同的对象(如文档中所示)。

更新:我被要求进一步澄清,所以这里有:

您认为您正在获取该对象的副本,但这并非严格正确。您将获得两个不同的Python对象,这些对象是独立创建的,但基于相同的数据库条目。那是因为每次使用索引操作符时都会查询数据库并创建一个新对象(前提是查询未经过评估)。

在您的情况下,您使用操作符两次,两次都命中数据库。第一次是在第二行:my_items[0].name = 'joe';第二次在第三行:my_items[0].save()。每次执行my_items[0]时,您都在使用运算符,查询数据库并创建新对象。因此,您将保存与修改后不同的对象。

答案 1 :(得分:0)

你在第二行写“my_itMes”的事实是否重要?

Item.objects.filter(pk = 1).update(name = 'Joe')

OR

myitem = Item.objects.get(id=1)
myitem.name = 'joe'
myitem.save()

https://docs.djangoproject.com/en/1.5/ref/models/instances/#updating-attributes-based-on-existing-fields

您要求的文件:

https://docs.djangoproject.com/en/1.5/topics/db/queries/#filtered-querysets-are-unique

每次优化QuerySet时,都会得到一个全新的QuerySet,它不会绑定到之前的QuerySet。每个细化都会创建一个独立且独特的QuerySet,可以存储,使用和重用。