Why can't "directly" change array elements of model objects in Django shell?

76 views
Skip to first unread message

Chris Seberino

unread,
Oct 7, 2011, 11:30:21 AM10/7/11
to Django users

I've noticed that this doesn't often work in Django shell...

x = MyModel.objects.all()
x[3].some_field = "new value"
x[3].save()

Rather, I must often do this...

temp = x[3]
temp.some_field = "new value"
temp.save()

*Sometimes* the first works and I don't know why.

Please advise.

Chris

Jacob Kaplan-Moss

unread,
Oct 7, 2011, 11:39:20 AM10/7/11
to django...@googlegroups.com

This is because `MyModel.objects.all()` isn't a list; it's a QuerySet.
That is, `MyModel.objects.all()` *doesn't* hit the database until you
say `x[3]`, at which point Django performs a query with a LIMIT and
OFFSET to just select that 3rd item. The entire list is never fetched.

See https://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated
for more details.

Jacob

Javier Guerra Giraldez

unread,
Oct 7, 2011, 12:29:18 PM10/7/11
to django...@googlegroups.com
On Fri, Oct 7, 2011 at 10:39 AM, Jacob Kaplan-Moss <ja...@jacobian.org> wrote:
>> *Sometimes* the first works and I don't know why.
>
> This is because `MyModel.objects.all()` isn't a list; it's a QuerySet.
> That is, `MyModel.objects.all()` *doesn't* hit the database until you
> say `x[3]`, at which point Django performs a query with a LIMIT and
> OFFSET to just select that 3rd item. The entire list is never fetched.

... and the QuerySet is free to override its own internal cache
anytime it wants. You know that `x[3]` will refer to the same
database record, but there's no guarantee that it will be the same
Python object.

--
Javier

Chris Seberino

unread,
Oct 7, 2011, 5:01:09 PM10/7/11
to Django users


On Oct 7, 10:39 am, Jacob Kaplan-Moss <ja...@jacobian.org> wrote:
> On Fri, Oct 7, 2011 at 10:30 AM, Chris Seberino <cseber...@gmail.com> wrote:
>
> > I've noticed that this doesn't often work in Django shell...
>
> > x = MyModel.objects.all()
> > x[3].some_field = "new value"
> > x[3].save()

> This is because `MyModel.objects.all()` isn't a list; it's a QuerySet.
> That is, `MyModel.objects.all()` *doesn't* hit the database until you
> say `x[3]`, at which point Django performs a query with a LIMIT and

OK. I understand. What is easiest way then to *force* my x[3] code
above to hit the database so that
my changes are permanent?

Andre Terra

unread,
Oct 7, 2011, 5:25:28 PM10/7/11
to django...@googlegroups.com
The easiest way would be to slice the list exactly how you were doing with x[3]... It doesn't get much easier than that.

I guess if you really need to spare yourself three keystrokes, you can do it like this:

>>> x = YourModel.objects.all()[3]
>>> x.foo = 'bar'
>>> x.save()


Cheers,
AT


--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.


Tom Evans

unread,
Oct 12, 2011, 6:57:55 AM10/12/11
to django...@googlegroups.com

x = list(MyModel.objects.all())


x[3].some_field = "new value"
x[3].save()

Cheers

Tom

fei

unread,
Oct 12, 2011, 4:43:19 PM10/12/11
to Django users
Instead, you can use the get() function,

x = MyModel.objects.get(id=3)
x.some_field = "new value"
x.save()

The difference between all() and get() is that all() will do a lazy
evaluation and get() will hit the physical database.

Fei

On Oct 12, 11:57 pm, Tom Evans <tevans...@googlemail.com> wrote:
Reply all
Reply to author
Forward
0 new messages