使用过滤器获取QuerySet时,可以使用以下代码轻松进行更改并保存操作:
qs = SomeModel.objects.filter(owner_id=123)
# suppose qs has 1 or many elements
last_login_time = qs[0].last_login_time
qs[0].last_login_time = datetime.now() # I expect it can assign the new value, but it won't
assertEquals(qs[0].last_login_time, last_login_time) # YES, it doesn't change
qs[0].save() #So it won't update the old record
在弄清楚之后,将使用以下代码,它可以正常工作:
qs = SomeModel.objects.filter(owner_id=123)
# suppose qs has 1 or many elements
obj = qs[0]
last_login_time = obj.last_login_time
obj.last_login_time = datetime.now() # I expect it can assign the new value, but it will
assertNotEquals(obj.last_login_time, last_login_time) # YES, it does change
obj.save() #So it will update the old record as expected
我遇到了一些朋友/同事使用第一种方法进行记录更新。而IMO,它很自然,很容易使用。 (当你输入qs [0] 和输入obj 时,它们的类型相同)
在阅读完代码(db.models.query)之后,可以找出原因。(当您下载QuerySet时,它将使用qs = self._clone()并且赋值不会发生任何变化)
可能的解决方案:
所以我想问:
答案 0 :(得分:0)
使用update
更新查询集中的字段。
答案 1 :(得分:0)
我不确定你在这里问的是什么。你是说这是一个bug吗?我不这么认为,它是明确定义的行为:查询集是惰性的,但在迭代或切片时会进行评估。每次切片时,都会得到一个新对象。这是切片本身不会导致非切片查询集被评估的事实的逻辑结果 - 如果结果尚未缓存,切片将仅使用LIMIT 1
执行单个数据库调用得到一个结果。否则,你会产生非常不良的副作用。
现在,如果您认为可以在文档中更好地解释这一点,那么欢迎您 - 并且鼓励 - 提交一个错误补丁,以便更好地解释它。