/usr/lib/python2.7/dist-packages/maasserver/signals.py is in python-django-maas 1.5.4+bzr2294-0ubuntu1.2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | # Copyright 2012-2014 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Signal utilities."""
from __future__ import (
absolute_import,
print_function,
unicode_literals,
)
str = None
__metaclass__ = type
__all__ = [
'connect_to_field_change',
]
from django.db.models.signals import (
post_delete,
post_init,
post_save,
pre_delete,
pre_save,
)
def connect_to_field_change(callback, model, fields, delete=False):
"""Call `callback` when any of `fields` on `model` are modified.
The triggering event is when a model object of the given type is either
saved to the database with any of the given fields having a different
value than it had originally; or, optionally, a model object of the given
type is deleted. In either case, no matter how many of the fields may
have been changed, the callback is invoked exactly once.
The signature of the callback method should be the following:
>>> def callback(instance, old_values, deleted):
...
pass
Where `instance` is the object which has just being saved to the
database, `old_values` is a tuple of the original values for `fields`
(in the same order as `fields`), and `deleted` indicates whether it was
a deletion that triggered the callback.
:param callback: The callback function.
:type callback: callable
:param model: Specifies a particular sender to receive signals from.
:type model: class
:param fields: Names of the fields to monitor.
:type fields: iterable of unicode
:param delete: Should the deletion of an object be considered a change
in the field?
:type delete: bool
"""
combined_fields_name = '__'.join(fields)
last_seen_flag = '_fields_last_seen_values__%s' % combined_fields_name
delta_flag = '_fields_delta__%s' % combined_fields_name
def snapshot_values(instance):
"""Obtain the tuple of `fields` values for `instance`."""
return tuple(
getattr(instance, field_name)
for field_name in fields
)
# Record the original values of the fields we're interested in.
def post_init_callback(sender, instance, **kwargs):
original_values = snapshot_values(instance)
setattr(instance, last_seen_flag, original_values)
post_init.connect(post_init_callback, sender=model, weak=False)
# Set 'delta_flag' to hold the fields' old and new values.
def record_delta_flag(sender, instance, **kwargs):
original_values = getattr(instance, last_seen_flag)
new_values = snapshot_values(instance)
setattr(instance, delta_flag, (new_values, original_values))
pre_save.connect(record_delta_flag, sender=model, weak=False)
# Call the `callback` if the field has changed.
def post_save_callback(sender, instance, created, **kwargs):
(new_values, original_values) = getattr(instance, delta_flag)
# Call the callback method is the field has changed.
if original_values != new_values:
callback(instance, original_values, deleted=False)
setattr(instance, last_seen_flag, new_values)
if delete:
pre_delete.connect(record_delta_flag, sender=model, weak=False)
def post_delete_callback(sender, instance, **kwargs):
(new_values, original_values) = getattr(instance, delta_flag)
callback(instance, original_values, deleted=True)
post_delete.connect(post_delete_callback, sender=model, weak=False)
post_save.connect(post_save_callback, sender=model, weak=False)
|