Opened 5 years ago
Closed 5 years ago
#31242 closed Bug (wontfix)
RelatedManager Set Semantics vs. Behavior
Reported by: | Clayton Daley | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 2.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The set
method is available on the many side of a 1:many or many:many. The documentation clearly states that the method will "Replace the set of related objects". Unfortunately, on the reverse side of a ForeignKey that is not nullable, this is not the actual behavior. Instead, it only add
s the submitted keys. I consider this as a bug full stop as the method shouldn't be available if the implementation does not follow its semantics.
The limitation arises because clear
and remove
are not available for a non-nullable reverse FK (and this restriction is actually documented in both of those methods). Unfortunately, the same limitation cascades to the set
method without documentation or exception.
Documentation is a good start, but this seems like a core function that you wouldn't necessary test in an application so I'm going to try to make the stronger case for a breaking change at the first opportunity. The long-run solution that aligns with the current implementation is to remove the set
method from non-nullable reverse FKs (like remove
and clear
), forcing apps to actually use add
. Since I consider the current behavior a bug, this only affects bugged users (but could be a breaking change for some). In practice, I'd throw an informative exception so users aren't confused by the sudden "loss" of (bugged) functionality.
This behavior was part of the original implementation added for #6707.
The docs stress that
set()
is a compound operation. It's explicitly stated thatremove()
is used. In their turn theremove()
docs state that the method doesn't exist onForeignKey
fields wherenull=False
.Removing
set()
would require a agreement via the DevelopersMailingList, but given the history I would not think it likely.