#34433: OneToOneField can only be saved one way
-------------------------------------+-------------------------------------
Reporter: Alexis Lesieur | Owner: nobody
Type: New feature | Status: closed
Component: Database layer | Version: 4.1
(models, ORM) |
Severity: Normal | Resolution: duplicate
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Alexis Lesieur):
First off apologies for missing the older ticket. I searched for similar
problems but...
Replying to [comment:3 Mariusz Felisiak]:
> > It's also problematic as foreigh keys work this way: (from my work
example)
>
> That's not true, on foreign keys you also cannot assign to a **reverse**
side.
You cannot "assign" as I may not just be able to do
`me.authored_pinnedmessage = ...` (to reference my earlier example) but I
can definitely do:
{{{
❯ PinnedMessage.objects.get(id=1).author
<ExternalUser: other.user (slack)>
❯ me = ExternalUser.objects.get(id=1)
❯ me.authored_pinnedmessages.add(p)
❯ me.save()
❯ PinnedMessage.objects.get(id=1).author
<ExternalUser: first.last (slack)>
}}}
And this works. So I can definitely use the reverse relationship.
Replying to [comment:3 Mariusz Felisiak]:
> > `.save()` "fails" silently, there is no way to know that the change
didn't take, especially when this happens:
>
> `save()` doesn't fail silently. By assigning an object to the
`.restaurant` you override a lazy reverse side of `OneToOneField` to a
"static" instance so it's not recognize as a relationship anymore.
I wholeheartedly disagree. Not only does it recognize the relationship
still as this proves:
{{{
❯ p1 = Place(name="1st place", address="1st address")
❯ p1.save()
❯ r1 = Restaurant(place=p1)
❯ r1.save()
❯ r2 = Restaurant(place=p2)
❯ r2.save()
❯ p1.restaurant = r2
❯ r2.place
<Place: 1st place the place>
}}}
It is clearly reflected. The relationship is definitely recognized.
It is just being ignored on save.
When as we showed it's being honored for ForeignKeys. Which the
documentation claims behaves the same.
I understand that from a pure implementation pov you're telling me that
doing `model.related_set.add(...)` is different than doing
`place.restaurant = new_place` here.
But that's really besides the point. From a user POV, the behavior is
highly unexpected, and really the main problem IMO (assuming you do keep
the current behavior) the documentation is really not addressing this
issue in any way.
In addition to the "OneToOneFields are just ForeignKeys with unique=True"
the documentation on how to use them clearly says:
> Set the place using assignment notation. Because place is the primary
key on Restaurant, the save will create a new restaurant:
{{{
>>> r.place = p2
>>> r.save()
>>> p2.restaurant
<Restaurant: Ace Hardware the restaurant>
>>> r.place
<Place: Ace Hardware the place>
}}}
>Set the place back again, using assignment in the reverse direction:
{{{
>>> p1.restaurant = r
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
}}}
Without addressing anywhere that you can't do p1.save() here. Which is
very counterintuitive. It is extremely expected that if I do
`p1.restaurant = r`, to apply/save that change, I should be doing
`p1.save()`.
If we're saying this is not applicable, please do call it out in the
documentation :-)
--
Ticket URL: <https://code.djangoproject.com/ticket/34433#comment:4>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/0107018713ef9337-7d6fa10c-81e7-462b-949a-456fb53d2409-000000%40eu-central-1.amazonses.com.