我希望做以下事情:
people = People.objects.filter(date=date)
person = people[0]
person['salary'] = 45000
最后一行导致错误:
object does not support item assignment
为了调试这样的事情,我总是发现从一些工作开始并逐行修改直到出现问题为止更容易。
我想在模板中修改要渲染的对象。如果我尝试:
person.salary = 45000
没有错误,但尝试
print person.salary
之后立即打印出原始值。更新:
在我的代码中我实际上在做:
people[0].salary = 45000
哪个不起作用。出于某种原因
person = people[0]
person.salary = 45000
有效吗?我认为这两段代码完全相同
答案 0 :(得分:5)
答案 1 :(得分:3)
查看ID,似乎当您为变量分配条目时,您会获得其副本,而不是其原始引用:
In [11]: people = People.objects.filter(salary=100)
In [12]: person = people[0]
In [13]: person.salary = 5000
In [14]: print person.salary
5000
In [15]: people[0].salary
Out[15]: 100
In [16]: id(people[0])
Out[16]: 35312400
In [17]: id(person)
Out[17]: 35313104
所以,让我们看一下它的深度。 您知道在Django中,只有在需要结果时才会评估QuerySets(延迟评估)。引用the Django documentation:
<强>切片即可。如限制QuerySet中所述,可以对QuerySet进行切片, 使用Python的数组切片语法。切片未评估的QuerySet 通常返回另一个未评估的QuerySet,但Django将执行 数据库查询,如果使用切片语法的“step”参数, 并将返回一个列表。切片已评估的QuerySet (部分或全部)也返回一个列表。
特别是,查看'django.db.models.query' source code,
def __getitem__(self, k):
"""
Retrieves an item or slice from the set of results.
"""
# some stuff here ...
if isinstance(k, slice):
qs = self._clone()
if k.start is not None:
start = int(k.start)
else:
start = None
if k.stop is not None:
stop = int(k.stop)
else:
stop = None
qs.query.set_limits(start, stop)
return k.step and list(qs)[::k.step] or qs
qs = self._clone()
qs.query.set_limits(k, k + 1)
return list(qs)[0]
您可以看到,当您使用切片时,您正在调用__getitem__
方法。
然后self._clone
方法将为您提供相同QuerySet的不同实例。这就是你得到不同结果的原因。
答案 2 :(得分:0)
Django模型提供的对象关系映射通过提供面向对象的接口来检索和操作数据,隐藏了与数据库交互的事实。
不幸的是,ORM抽象并不完美,当ORM语义与直觉不匹配时,存在各种情况。在这些情况下,您需要调查底层SQL层上发生的情况,以找出问题的原因。
你的问题源于:
people = People.objects.filter(date=date)
不执行任何SQL查询。
people[0]
如果通过调用:修改结果对象,执行SELECT a, b, c, .. FROM T WHERE filter
people[0].salary = 45000
修改不会保存到DB,因为未调用save()
方法。对people[0]
的下一次调用再次执行SQL查询,该查询不返回未保存的修改。
当遇到这样的问题时,Django Debug Toolbar可以极大地帮助识别哪些语句执行哪些SQL查询。