Why do Django model-fields get out of sync when traversing relationships?
I'm running into an issue accessing a changed model field, traversing relationships in a Django 1.3 app. Changes committed to the database are not being reflected by in-memory objects. I'm using the User() object from Auth Middleware, linking it to a custom Profile() object:
User() <---one-to-one---> Profile()
The issue comes up when accessing the email
field for a User():
$ python manage.py shell
>>> from django.contrib.auth.models import User
>>> from myproject.myapp.models import Profile
>>>
>>> user = User.objects.get(pk=1)
>>> profile = user.profile
>>> user.email
u'old@example.com' # OK.
>>> profile.user.email
u'old@example.com' # OK.
>>>
>>> user.email = 'new@example.com' # 1) Changes email address.
>>> user.save() 开发者_开发知识库 # 2) Commits to database.
>>> user.email
'new@example.com' # 3) Changes reflected in user.email. Good.
>>> profile.user.email
u'old@example.com' # 4) Wrong. This is the old incorrect email.
>>> user.profile.user.email
u'old@example.com' # 5) Also wrong.
>>>
>>> profile = Profile.objects.get(user=user)
>>> profile.user.email
u'new@example.com' # 6) If we re-query the DB, things are OK.
Why do things get out of sync in steps #4 and #5? I'm baffled by #5, going from the saved user object, to the profile, and back to the same saved user object.
Obviously there is some sort of caching going on, but I'm not sure of the logic/algorithm behind it. Anyone have an idea of what's happening, and the best way to approach this in code? Thanks for any insight you can offer! :)
The SingleRelatedObjectDescriptor
descriptor responsible for transparently looking up the related object checks for a cached version of the related object in _<fieldname>_cache
in the Model instance, caching it the first time it is retrieved.
Django's ORM doesn't use an identity map, so changes to one Model instance aren't automatically reflected in other instances which existing references are held to.
profile.user
is not user
. What you are looking at is another cached copy of the model that Django's ORM had previously pulled from the database. If you absolutely must have the latest value then you will need to requery each time.
精彩评论