in src/olympia/amo/models.py [0:0]
def save(self, *args, **kwargs):
"""
Save changes to the model instance.
If _signal=False is in `kw` the on_change() callbacks won't be called.
"""
# When saving an existing instance, if the caller didn't specify
# an explicit update_fields and _dynamic_update_fields is absent or
# True, we attempt to find out which fields were changed and only
# save those. This allows for slightly better performance as we don't
# keep re-saving the same data over and over again, but also avoids
# overwriting data that has changed in the meantime.
# Fields with auto_now=True will be included all the time.
#
# Note that deferred fields will be included in the list of changed
# fields if they are loaded afterwards, even if their value does not
# change.
if (
self.pk
# Just having self.pk is not enough, we only really want to catch
# UPDATE calls and the caller could be doing Model(pk=1).save().
# Django save() implementation uses the special _state attribute
# for this.
and self._state.adding is False
and kwargs.get('update_fields') is None
and kwargs.pop('_dynamic_update_fields', True)
):
fields = [f.attname for f in self._meta.concrete_fields]
concrete_initial_attrs = [
(k, v) for k, v in self._initial_attrs.items() if k in fields
]
current_attrs = [(k, self.__dict__[k]) for k, v in concrete_initial_attrs]
changed_attrs = (
set(current_attrs)
- set(concrete_initial_attrs)
# Never include primary key field - it might be set to None
# initially in _initial_attrs right after a call to create()
# even though self.pk is set.
- {(self._meta.pk.name, self.pk)}
)
auto_now_fields = [
f.name for f in self._meta.fields if getattr(f, 'auto_now', False)
]
kwargs['update_fields'] = [k for k, v in changed_attrs] + auto_now_fields
signal = kwargs.pop('_signal', True)
result = super().save(*args, **kwargs)
if signal and self.__class__ in _on_change_callbacks:
self._send_changes(self._initial_attrs.copy(), dict(self.__dict__))
# Reset initial_attr to be ready for the next save.
updated_fields = kwargs.get('update_fields')
self._reset_initial_attrs(
attrs={k: self.__dict__[k] for k in updated_fields}
if updated_fields
else None
)
return result