yossi
yossi

Reputation: 13315

why django querysey index operator return a copy of the object

I know that django querysey is a generator and not a list.

my_items = Item.objects.filter(id = 1)
my_items[0].name = 'joe'
my_items[0].save()

In the example my_items[0] is a copy of the object so the save will not modify the object.
while this will work (will not create a copy)

my_items = Item.objects.filter(id = 1)
my_item = my_items[0]
my_item.name = 'joe'
my_item.save()

Where in django docs (or any where else) it explain this behavior ? And why did they choose to return a copy of the object and not the object itself ?

Upvotes: 0

Views: 237

Answers (2)

Ludwik Trammer
Ludwik Trammer

Reputation: 25052

It is documented in the section about querysets and caching. It's not just a copy of an existing object. Every time you do this Django makes a separate query to the database, and a new object is created based on the response. Here's an example provided by the documentation:

>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again

However if your queryset is already evaluated, getting an object using index operator will not hit the database, and you will get the same object every time (as shown in the documentation).

Update: I was asked to clearify further, so here it goes:

You think you are getting a copy of the object, but that's not strictly true. You are getting two different Python objects, created independently, but based on the same database entry. That's because every time you use the index operator the database is queried and a new object is created (provided the query wasn't evaluated before).

In your case you use the operator two times, both times hitting the database. The first time is in the second line: my_items[0].name = 'joe'; and the second time in the third line: my_items[0].save(). Every time you do my_items[0] you are using the operator, querying the database and creating a new object. As a result you are saving a different object than you modified.

Upvotes: 4

Marcelo Zárate
Marcelo Zárate

Reputation: 296

Does the fact that you wrote "my_itMes" in the second line important?

Item.objects.filter(pk = 1).update(name = 'Joe')

OR

myitem = Item.objects.get(id=1)
myitem.name = 'joe'
myitem.save()

https://docs.djangoproject.com/en/1.5/ref/models/instances/#updating-attributes-based-on-existing-fields

And the documentation you asked for:

https://docs.djangoproject.com/en/1.5/topics/db/queries/#filtered-querysets-are-unique

Each time you refine a QuerySet, you get a brand-new QuerySet that is in no way bound to the previous QuerySet. Each refinement creates a separate and distinct QuerySet that can be stored, used and reused.

Upvotes: 0

Related Questions