我有一个Django模型:
class QuestionAnswer(models.Model):
question = models.ForeignKey(Question)
marks = models.FloatField(null=True)
graded = models.IntegerField()
现在在命令行中我做:
>>> 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
graded
字段未更新。
但是当我这样做时:
>>> qa = QuestionAnswer.objects.get(pk=12345)
>>> qa.graded
0
>>> qa.graded = 1
>>> qa.save()
>>> qa = QuestionAnswer.objects.get(pk=12345)
>>> qa.graded
1
为什么objects.filter
没有更新字段,objects.get
有效?
答案 0 :(得分:9)
试试这个:
>>> 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
通过使用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()
显而易见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
中数据库中的更改。
但是,如果您在切片之前评估整个查询集,则会缓存所有结果,并且以下将工作:
{{1}}
答案 1 :(得分:3)
在ORM查询中使用过滤器更新
时尝试此操作QuestionAnswer.objects.filter(pk=12345).update(graded=1)
答案 2 :(得分:2)
filter
返回QuerySet
(即使它看起来像一个列表)。在django中,querysets are lazy表示只在需要时对它们进行评估。
get
返回不是"懒惰的实际对象&#34 ;;这就是为什么你的改变似乎立即生效。
要解决您的问题,您需要评估查询集。您可以通过迭代它(在for循环中)或将其转换为列表来完成此操作。
但是,由于您使用主键进行过滤,因此您应该使用get
;但请记住get
会在找不到密钥或者返回多个对象时引发异常:
try:
foo = Foo.objects.get(pk=-1)
except Foo.DoesNotExist:
print('There is no foo with pk 1')
except Foo.MultipleObjectsReturned:
print('Oh no! Multiple foos with key 1!')
print('I am the foo with key 1: {}'.format(foo))