django queryset weirdness

I needed to reset the django admin password and found this page which tells us how to do this. It did not work for me, however I tried to get the user object explicitly, reset the password and save it and it worked!
Here is a session describing the behavior:

> python manage.py shell
In [1]: from django.contrib.auth.models import User
In [2]: u=User.objects.all()
In [3]: u[0].password
Out[3]: ’sha1$0913d$6c5cfefb89b3c77dc8573e466a943c7acd177f6b’
In [9]: u[0].set_password(’testme’)
In [10]: u[0].save()
In [11]: u[0].password
Out[11]: ’sha1$0913d$6c5cfefb89b3c77dc8573e466a943c7acd177f6b’
In [12]: q=User.objects.get(id=1)
In [13]: q
Out[13]: <user : root>
In [14]: q.set_password(’testme’)
In [15]: q.save()
In [16]: q.password
Out[16]: ’sha1$24e9c$868ff39f08c3bde96397e33ea6a8847a658a16bc’

Maybe this is related to queryset caching, which would print the same password even after calling set_password. But it looks like in the first method, the password does not even get written to the database. This might be a bug. I will need to run more tests and report (or possibly patch) it…

Update: Perhaps I am not clear in the above post. The weirdness is that in the above two scenarios u[0] and q should essentially reference the same user object, but calling set_password (and later save) method on the u[0] reference does not seem to work (i.e. the password attribute remains unchanged and changed password cannot be used on the admin pages) but calling the same method on q reference seems to work!

Update2:I got it finally. Thanks all (Esp SmileyChris) ! every array slice is a new query! so in the first solution, I need this to make it work:

u=User.objects.all()
u[0].password # to display current hash (Query #1)
q=u[0] # (Query #2)
q.set_password(’testme’)
q.save()
q.password
u[0].password # (Query #3) this should print updated hash!

Comments 5

  1. SmileyChris wrote:

    The problem here isn’t queryset caching, but the fact that QuerySet objects use custom array slicing (http://www.djangoproject.com/documentation/db-api/#limiting-querysets). Every time you were doing u[0], you were getting the original object from the database again.

    Posted 09 Apr 2007 at 12:07 pm
  2. Gábor Farkas wrote:

    hi,

    maybe i overlooked something, but i can’t see any problem with the example you showed. could you perhaps explain the problem in more detail?

    Posted 09 Apr 2007 at 12:32 pm
  3. amit wrote:

    SmileyChris: But shouldn’t u[0].save() change the value in the database ? Infact, after executing the u[0].save() function, I did another User.objects.all() call and it still shows the old password.

    Gábor: watch the password attribute, it needs to change after save() function, but it did not change the first time, but changed when the save method is accessed via q reference.

    Posted 09 Apr 2007 at 1:47 pm
  4. SmileyChris wrote:

    Saving a password isn’t done inside of set_password so this is what happens:
    1. >>> u[0].save_password(’testme’)
    2. The user’s details are retrieved from the database and a User instance is created.
    3. The password is changed for this instance (but it hasn’t been saved).
    4. >>> u[0].save()
    5. The user’s details are retreived *again* from the database and a *new* User instance is created.
    6. This new instance is saved (and since no data has changed for this second instance, you won’t get your new password).

    Posted 09 Apr 2007 at 2:31 pm
  5. WorldMaker wrote:

    SmileyChris is correct *everytime* you slice a queryset it runs the query. That is: every u[0] is a different object, so u[0].save() just resaves exactly what’s in the database already, because it refreshes on u[0]. Unfortunately, QuerySet just doesn’t have any sort of “slice caching”, so everytime you use [] you need to cache it yourself by saving it to a seperate name (in the case of a list, eg [:3], you want to pass it through list() to run the query if you aren’t using a for loop). This should probably be better documented…

    (I’ve been bitten by this myself… One example I’ve yet to fix is the random photo link on my frontpage: due to the order_by(’?') the random photo has an entirely different random alt tag and links to a further different random photo.)

    Posted 09 Apr 2007 at 2:46 pm

Post a Comment

Your email is never published nor shared. Required fields are marked *