Merge pull request #556 from meanmail/master

Don't use `post_init` signal for initialize tracker
This commit is contained in:
Jelmer 2024-03-21 08:19:15 +01:00 committed by GitHub
commit 473ee7459c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 21 additions and 5 deletions

View file

@ -104,3 +104,4 @@
| Éric Araujo <merwok@netwok.org>
| Őry Máté <ory.mate@cloud.bme.hu>
| Nafees Anwar <h.nafees.anwar@gmail.com>
| meanmail <github@meanmail.dev>

View file

@ -1,10 +1,15 @@
Changelog
=========
4.5.0
-----
- Don't use `post_init` signal for initialize tracker
4.4.0 (2024-02-10)
------------------
- Add support for `Python 3.11`
- Add support for `Python 3.11`
- Add support for `Python 3.12`
- Drop support for `Python 3.7`
- Add support for `Django 4.2`

View file

@ -328,9 +328,9 @@ FieldTracker implementation details
This is how ``FieldTracker`` tracks field changes on ``instance.save`` call.
1. In ``class_prepared`` handler ``FieldTracker`` patches ``save_base`` and
``refresh_from_db`` methods to reset initial state for tracked fields.
2. In ``post_init`` handler ``FieldTracker`` saves initial values for tracked
1. In ``class_prepared`` handler ``FieldTracker`` patches ``save_base``,
``refresh_from_db`` and ``__init__`` methods to reset initial state for tracked fields.
2. In the patched ``__init__`` method ``FieldTracker`` saves initial values for tracked
fields.
3. ``MyModel.save`` changes ``update_fields`` in order to store auto updated
``modified`` timestamp. Complete list of saved fields is now known.

View file

@ -343,7 +343,7 @@ class FieldTracker:
wrapped_descriptor = wrapper_cls(field_name, descriptor, self.attname)
setattr(sender, field_name, wrapped_descriptor)
self.field_map = self.get_field_map(sender)
models.signals.post_init.connect(self.initialize_tracker)
self.patch_init(sender)
self.model_class = sender
setattr(sender, self.name, self)
self.patch_save(sender)
@ -356,6 +356,16 @@ class FieldTracker:
tracker.set_saved_fields()
instance._instance_initialized = True
def patch_init(self, model):
original = getattr(model, '__init__')
@wraps(original)
def inner(instance, *args, **kwargs):
original(instance, *args, **kwargs)
self.initialize_tracker(model, instance)
setattr(model, '__init__', inner)
def patch_save(self, model):
self._patch(model, 'save_base', 'update_fields')
self._patch(model, 'refresh_from_db', 'fields')