On Sun, May 12, 2013 at 3:05 PM, Chris Wilson <[email protected]> wrote:

> Hi all,
>
>
> On Sun, 12 May 2013, Shai Berger wrote:
>
>  those should probably be updated (on remote objects!) too, or else some
>>>> serious inconsistencies may be created (when the _id field changes, that
>>>> is).
>>>>
>>>
>> aa= A.objects.get(...)
>> bb= aa.b
>> (some other operation, changing aa.b_id in the database)
>> aa.refresh()
>>
>> Now -- unless we do something about it -- bb.a is still aa, but aa.b is
>> not bb
>> and not even equal to it; thus, "bb.a.b == bb" is false, which currently
>> cannot happen without serious meddling if I'm not mistaken.
>>
>
> Hibernate (as an implementation of the Java Persistence API, JPA) tries to
> do things like this by implementing a global cache of objects loaded from
> the database, so that there's only one copy of A and B in memory, which all
> references point to.
>
> This makes it possible for A, when its link to B changes to point to a
> different object B', to find all the instances of B in memory (because
> there's only one, and it's in the object cache) and update them to no
> longer point back to A.
>
> However it does this at enormous cost in flexibility, sanity and error
> recovery. I strongly recommend against going down this route:
> http://blog.old.aptivate.org/**2010/11/26/hibernate-ejb-and-**
> the-unique-constraint/<http://blog.old.aptivate.org/2010/11/26/hibernate-ejb-and-the-unique-constraint/>
>
> It's always possible to have an out-of-date model object in memory with
> Django, with or without refresh() (which just allows us to update it
> manually). I suggest we let that sleeping dog lie.


It does make sense to do this though, in the particular case of one-to-one
relationships (for the same reasons it makes sense to cache back-references
in one-to-one relationships). The reason is that this maintains a
python-only invariant that is independent of whether the relationship is
persistent in the database. There's no attempt to update all model
instances of the referred-to model, only the single one that is currently
referred to by the Python instance. This is consistent with the behavior of
setting a OneToOneField to None. For example consider the following:

bb = B()
bb.save()
aa = A(b=bb)
aa.save()
assert aa.b is bb
assert bb.a is aa   # back-reference is cached

aa.b = None   # back-reference is cleared
assert aa.b is None
assert bb.a is None

This should be consistent with the behavior when .refresh() is called -- if
that involves clearing aa.b, then bb.a should also be cleared, it's that
simple. Ideally this is done by just setting all fields via setattr(),
which will trigger this code (and any arbitrary code for user-defined
fields Django doesn't know about). In short the following should be
equivalent to the previous example:

bb = B()
bb.save()
aa = A(b=bb)
aa.save()
assert aa.b is bb
assert bb.a is aa   # back-reference is cached

aaa = A.objects.get(id=aa.id)
aaa.b = None
aaa.save()

aa.refresh()   # back-reference is cleared
assert aa.b is None
assert bb.a is None

Hopefully that clears things up.

Best,
Alex Ogier

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to