views:

742

answers:

3

This doesn't work:

>>> pa = Person.objects.all()
>>> pa[2].nickname
u'arst'
>>> pa[2].nickname = 'something else'
>>> pa[2].save()
>>> pa[2].nickname  
u'arst'

But it works if you take

   p = Person.objects.get(pk=2)

and change the nick.

Why so.

+2  A: 

If you assigned your pa[2] to a variable, like you do with Person.objects.get(pk=2) you'd have it right:

pa = Person.objects.all()
print pa[2].nickname
'Jonny'
pa[2].nickname = 'Billy'
print pa[2].nickname
'Jonny'

# when you assign it to some variable, your operations 
# change this particular object, not something that is queried out each time
p1 = pa[2]
print p1.nickname 
'Jonny'
p1.nickname = 'Billy'
print p1.nickname 
'Billy'

This has nothing to do with the method you pull the objects from database.

And, btw, django numbers PrimaryKeys starting from 1, not 0, so

Person.objects.all()[2] == Person.objects.get(pk=2)
False
Person.objects.all()[2] == Person.objects.get(pk=3)
True
kender
+1 Great answer, very informative (especially the last part...)
Roee Adler
It would be helpful to mention that all() is a QuerySet, not an actual list. http://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-all-objects
S.Lott
Thanks for pointing it out
kender
Yea, this way it works, of you assign it to a variable. But why changes on `pa` are not reflected
Lakshman Prasad
+6  A: 
>>> type(Person.objects.all())
<class 'django.db.models.query.QuerySet'>

>>> pa = Person.objects.all() # Not evaluated yet - lazy
>>> type(pa)
<class 'django.db.models.query.QuerySet'>

DB queried to give you a Person object

>>> pa[2]

DB queried again to give you yet another Person object.

>>> pa[2].first_name = "Blah"

Let's call this instance PersonObject1 that resides in memory. So it's equivalent to something like this:

>>> PersonObject1.first_name = "Blah"

Now let's do this:

>>> pa[2].save()

The pa[2] again queries a db an returns Another instance of person object, say PersonObject2 for example. Which will be unchanged! So it's equvivalent to calling something like:

PersonObject2.save()

But this has nothing to do with PersonObject1.

drozzy
Very well explained! Thanks!
Lakshman Prasad
+1  A: 

Person.objects.all() returns a QuerySet, which is lazy (doesn't perform a DB query until data is requested from it). Slicing a QuerySet (pa[2]) performs a database query to get a single row from the database (using LIMIT and OFFSET in SQL). Slicing the same QuerySet again doesn't do the DB query again (results are cached) but it does return a new instance of the model. Each time you access pa[2] you are getting a new Person instance (albeit with all the same data in it).

Carl Meyer