我有一个Django模型:
class QuestionAnswer(models.Model):
question = models.ForeignKey(Question)
marks = models.FloatField(null=True)
graded = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)
现在在命令行中我做:
>>> qa = QuestionAnswer.objects.filter(pk=12345)
>>> qa[0].graded
0
>>> qa[0].graded = 1
>>> qa[0].save()
>>> qa = QuestionAnswer.objects.filter(pk=12345)
>>> qa.graded
0
Run Code Online (Sandbox Code Playgroud)
该graded字段未更新.
但当我这样做时:
>>> qa = QuestionAnswer.objects.get(pk=12345)
>>> qa.graded
0
>>> qa.graded = 1
>>> qa.save()
>>> qa = QuestionAnswer.objects.get(pk=12345)
>>> qa.graded
1
Run Code Online (Sandbox Code Playgroud)
为什么不objects.filter更新字段但objects.get有效?
试试这个:
>>> qs = QuestionAnswer.objects.filter(pk=12345)
>>> qa = qs[0]
>>> qa.graded
0
>>> qa.graded = 1
>>> qa.save()
>>> qa = QuestionAnswer.objects.filter(pk=12345)
>>> qa[0].graded
This should be 1
Run Code Online (Sandbox Code Playgroud)
通过使用qa[0],您实际上并没有修改和保存相同的对象(即使它们代表相同的SQL数据).
这是因为查询集是惰性的:它们只在您实际尝试使用查询集将返回的数据时才执行sql查询.切片使用查询集的方式,执行查询但不会缓存结果.这意味着无论何时使用qa[0],都会执行新查询,并将该数据保存在新创建的模型实例中.你实际做的是:
>>> qs = QuestionAnswer.objects.filter(pk=12345)
>>> qa1 = qs.get()
>>> qa1.graded
0
>>> qa2 = qs.get()
>>> qa2.graded = 1
>>> qa3 = qs.get()
>>> qa3.save()
Run Code Online (Sandbox Code Playgroud)
显而易见的是qa1,qa2并且qa3是模型的不同实例:虽然它们具有相同的属性值(表示相同的数据库数据),但实际上它们保存在内存中的不同位置并且彼此完全分离.更改graded属性qa2不会以任何方式影响qa3,因此qa3保存时,更改qa2将不会反映在数据库中的更改中.
但是,如果要在切片之前评估整个查询集,则会缓存所有结果,并且以下方法可以正常工作:
>>> qs = QuestionAnswer.objects.filter(pk=12345)
>>> qs[0] is qs[0]
False # These are not the same objects in memory...
>>> bool(qs) # This forces evaluation of the entire queryset
True
>>> qs[0] is qs[0]
True # ... but these are!
>>> qs[0].graded
0
>>> qs[0].graded = 1
>>> qs[0].save()
>>> qs = QuestionAnswer.objects.filter(pk=12345)
>>> qs[0].graded
1
Run Code Online (Sandbox Code Playgroud)