#17332: Doing a save after primary key has changed should raise an error
-------------------------------------+-------------------------------------
Reporter: akaariai | Owner: nobody
Type: Uncategorized | Status: new
Component: Database layer | Version: 1.3
(models, ORM) | Resolution:
Severity: Normal | Triage Stage:
Keywords: | Unreviewed
Has patch: 1 | Needs documentation: 1
Needs tests: 1 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by akaariai):
* cc: akaariai (added)
* needs_docs: => 1
* has_patch: 0 => 1
* needs_tests: => 1
* needs_better_patch: => 0
Comment:
A proof of concept patch attached.
Some notes about the implementation:
- The implementation is based on field.get_immutable_value(obj). By
default this returns the fields value as is. This is set to
obj._state.old_pk_values, and then in save we compare the new pk value to
that. If changes -> deprecation warning.
- I did some cleanup to how model._state is updated, this was required
as there was a lot of non-DRYness after my changes.
- I also did some cleanups to model.save(). I think I also found a bug
related to transaction handling, I will create another ticket about that.
- There is no compatibility flag, you can get the old behavior back by
explicitly rotating the PK value to None and then to new value. That is:
{{{
obj = qs.get(pk=1); obj.pk = 2; obj.save() -> deprecation warning
obj = qs.get(pk=1); obj.pk = None; obj.pk = 2; obj.save() -> no warning,
and will work later on.
}}}
There is no safe get_immutable_value for 3rd party fields. The idea is
that custom fields have two releases to implement this if needed. If they
fail to do this and are mutable based, then the tracking of changes will
not work. I think this approach is now pretty good, although the current
patch does not have tests. How to test `PendingDeprecationWarnings`?
The bad news about this approach is that model `__init__` is now 10-20%
slower for somewhat simple models (20% for just integer pk, 10% when there
are additional 10 integer fields). The speed difference would likely be
much smaller if the fields were large strings, but this still feels a bit
bad. I don't know how to make this any faster, except if we track just the
"main" primary key, that is, we skip tracking of parent class primary
keys.
The next problem is what to do to `ModelForms`. They would need to have an
editable field when inserting, and non-editable field when editing an
already existing model. Bad news is that `ModelForms` do not support non-
editable fields. A html attribute editable="false" + validation might
work, but isn't too pretty approach...
--
Ticket URL: <https://code.djangoproject.com/ticket/17332#comment:1>
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 post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.