Django对象更改模型字段

3 投票
3 回答
5875 浏览
提问于 2025-04-15 11:50

这个不行:

>>> pa = Person.objects.all()
>>> pa[2].nickname
u'arst'
>>> pa[2].nickname = 'something else'
>>> pa[2].save()
>>> pa[2].nickname  
u'arst'

但是如果你用

   p = Person.objects.get(pk=2)

并且换个昵称,就可以了。

这是为什么呢?

3 个回答

2

Person.objects.all() 这个命令会返回一个叫做 QuerySet 的东西,它是懒惰的,也就是说,直到你真正需要数据的时候,它才会去数据库查询。比如,当你用 pa[2] 这种方式切片 QuerySet 时,它会去数据库查询,拿到一行数据(在SQL中用的是LIMIT和OFFSET)。但是,如果你再次对同一个 QuerySet 进行切片,它就不会再去数据库查询了,因为结果已经被缓存了。不过,它会返回一个新的模型实例。每次你访问 pa[2] 时,实际上都是在获取一个新的 Person 实例(虽然里面的数据都是一样的)。

5

如果你把你的 pa[2] 赋值给一个变量,就像你用 Person.objects.get(pk=2) 这样做,你就会得到正确的结果:

pa = Person.objects.all()
print pa[2].nickname
'Jonny'
pa[2].nickname = 'Billy'
print pa[2].nickname
'Jonny'

# when you assign it to some variable, your operations 
# change this particular object, not something that is queried out each time
p1 = pa[2]
print p1.nickname 
'Jonny'
p1.nickname = 'Billy'
print p1.nickname 
'Billy'

这和你从数据库中获取对象的方法没有关系。

顺便说一下,django 的主键(PrimaryKey)是从 1 开始编号的,而不是从 0 开始,所以

Person.objects.all()[2] == Person.objects.get(pk=2)
False
Person.objects.all()[2] == Person.objects.get(pk=3)
True
11
>>> type(Person.objects.all())
<class 'django.db.models.query.QuerySet'>

>>> pa = Person.objects.all() # Not evaluated yet - lazy
>>> type(pa)
<class 'django.db.models.query.QuerySet'>

数据库查询给你一个“人”的对象。

>>> pa[2]

数据库又查询一次,给你另一个“人”的对象。

>>> pa[2].first_name = "Blah" 

我们把这个在内存中的实例叫做PersonObject1。它就像这样:

>>> PersonObject1.first_name = "Blah"

现在我们来做这个:

>>> pa[2].save() 

pa[2]再次查询数据库,返回另一个“人”的对象,比如叫PersonObject2。这个对象不会改变!所以这就相当于调用类似于:

PersonObject2.save()

但是这和PersonObject1没有任何关系。

撰写回答