Django objects.filter不是更新字段,而是objects.get

时间:2014-04-10 06:44:09

标签: python django orm

我有一个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有效?

3 个答案:

答案 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()

显而易见qa1qa2qa3是您模型的不同实例:虽然它们具有相同的属性值(表示相同的数据库数据),但它们实际上是保存在内存中的不同位置,并且彼此完全分开。更改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))