Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django objects.filter is not updating field but objects.get is

Tags:

python

orm

django

I have a Django model :

class QuestionAnswer(models.Model):
   question = models.ForeignKey(Question)
   marks = models.FloatField(null=True)
   graded = models.IntegerField()

Now in command line I do:

>>> 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

The graded field is not updated.

But when I do:

>>> qa = QuestionAnswer.objects.get(pk=12345)
>>> qa.graded 
0
>>> qa.graded = 1
>>> qa.save()
>>> qa = QuestionAnswer.objects.get(pk=12345)
>>> qa.graded
1

Why does objects.filter not updating the field but objects.get works?

like image 962
Coderaemon Avatar asked Dec 09 '22 08:12

Coderaemon


2 Answers

Try this:

>>> 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

By using qa[0], you're not actually modifying and saving the same object (even though they represent the same SQL data).

This is due to the fact that querysets are lazy: they only execute the sql query when you actually try to use the data that the queryset would return. The way slices work with querysets, the query is executed but the result will not be cached. This means that whenever you use qa[0], a new query is executed, and that data is saved in a newly created model instance. What you are effectively doing is this:

>>> qs = QuestionAnswer.objects.filter(pk=12345)
>>> qa1 = qs.get()
>>> qa1.graded
0
>>> qa2 = qs.get()
>>> qa2.graded = 1
>>> qa3 = qs.get()
>>> qa3.save()

It should be obvious that qa1, qa2 and qa3 are different instances of your model: while they have the same attribute values (as the represent the same database data), they are actually saved in different places in memory and are completely separate from each other. Changing the graded attribute on qa2 will not in any way affect qa3, so when qa3 is saved, the changes to qa2 won't be reflected in the changes in the database.

However, if you were to evaluate the entire queryset before slicing, all results would be cached, and the following would work:

>>> 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
like image 53
knbk Avatar answered Dec 11 '22 09:12

knbk


Try out this when you use filter in ORM query to update

QuestionAnswer.objects.filter(pk=12345).update(graded=1)
like image 42
Shanki Avatar answered Dec 11 '22 09:12

Shanki