Start with the following models using django==3.2.12:
from django.db import models
class Root(models.Model):
pass
class Leaf(models.Model):
root = models.OneToOneField(Root, related_name='leaf_data', on_delete=models.CASCADE)
Run the following in the shell:
>>> from myapp.models import Root, Leaf
>>> root = Root()
>>> root.save()
>>> leaf = Leaf(root=root)
>>> leaf.save()
>>> root
<Root: Root object (1)>
>>> leaf
<Leaf: Leaf object (1)>
>>> new_root = Root()
>>> new_root.save()
>>> new_root
<Root: Root object (2)>
>>> root.leaf_data
<Leaf: Leaf object (1)>
>>> leaf = root.leaf_data
>>> leaf.pk = None
>>> leaf.root = new_root
>>> leaf.save()
>>> leaf.root
<Root: Root object (2)>
>>> root.leaf_data
<Leaf: Leaf object (2)>
Why does the original root.leaf_data reference change? I would expect that by setting leaf.pk = None and leaf.root = new_root that the original root/leaf structure would remain intact. I’m trying to create a full duplicate from the original.
>Solution :
I didn’t change on db. If you do root.refresh_from_db() root.leaf_data should be <Leaf: Leaf object (1)>.
What happened is you used root.leaf_data object to create another Leaf. After save django hydrated this Leaf instance with data of newly created leaf – <Leaf: Leaf object (2)>. But root still points at this object!
If you created new Leaf and not reused the instance the problem wouldn’t occur 😀