def watch(self, call_on_created=None): self._call_on_created = (self._call_on_created if call_on_created is None else call_on_created) # initialize investigator self._investigator = Investigator(self.model, include=[self.attr]) # register the receivers register_reciever(self.model, pre_save, self._pre_save_receiver) register_reciever(self.model, post_save, self._post_save_receiver)
class ValueWatcher(WatcherBase): """ Watcher field for watching non relational field such as CharField. """ def __init__(self, model, attr, callback, call_on_created=True): super(ValueWatcher, self).__init__(model, attr, callback) self._call_on_created = call_on_created def watch(self, call_on_created=None): self._call_on_created = (self._call_on_created if call_on_created is None else call_on_created) # initialize investigator self._investigator = Investigator(self.model, include=[self.attr]) # register the receivers register_reciever(self.model, pre_save, self._pre_save_receiver) register_reciever(self.model, post_save, self._post_save_receiver) def unwatch(self): unregister_reciever(self.model, pre_save, self._pre_save_receiver) unregister_reciever(self.model, post_save, self._post_save_receiver) def _pre_save_receiver(self, sender, instance, **kwargs): if kwargs.get('row', False): # should not call any callback while it is called via fixtures or # so on return self._investigator.prepare(instance) def _post_save_receiver(self, sender, instance, created, **kwargs): if kwargs.get('row', False): # should not call any callback while it is called via fixtures or # so on return if self._call_on_created and created: self.call(instance) # if investigator yield any field_name, call the callback if any(self._investigator.investigate(instance)): self.call(instance)
def watch(self, call_on_created=None, include=None, exclude=None): self._call_on_created = (self._call_on_created if call_on_created is None else call_on_created) include = include or self.include exclude = exclude or self.exclude self._investigator = Investigator(self.related_model, include=include, exclude=exclude) # register the receivers register_reciever(self.model, pre_save, self._pre_save_receiver, sender=self.related_model) register_reciever(self.model, post_save, self._post_save_receiver, sender=self.related_model) register_reciever(self.model, post_save, self._post_save_receiver_for_creation)
class RelatedWatcherBase(WatcherBase): """ A base watcher field for relational field such as ForeignKey, ManyToMany """ def __init__(self, model, attr, callback, call_on_created=True, include=None, exclude=None): """ Construct watcher field Args: model (model): A target model class attr (str): A name of attribute callback (fn): A callback function call_on_created (bool): Call callback when the new instance is created include (None, list, tuple): A related object field name list which will be investigated to determine the modification exclude (None, list, tuple): A related object field name list which won't be investigated to determine the modification """ super(RelatedWatcherBase, self).__init__(model, attr, callback) self.include = include self.exclude = exclude self._call_on_created = call_on_created @property @lru_cache(settings.OBSERVER_LRU_CACHE_SIZE) def is_reversed(self): return self.get_field().model != self._model @property @lru_cache(settings.OBSERVER_LRU_CACHE_SIZE) def related_model(self): field = self.get_field() if self.is_reversed: return field.model return field.related.parent_model @property @lru_cache(settings.OBSERVER_LRU_CACHE_SIZE) def related_attr(self): field = self.get_field() if self.is_reversed: return field.name return field.related.get_accessor_name() def watch(self, call_on_created=None, include=None, exclude=None): self._call_on_created = (self._call_on_created if call_on_created is None else call_on_created) include = include or self.include exclude = exclude or self.exclude self._investigator = Investigator(self.related_model, include=include, exclude=exclude) # register the receivers register_reciever(self.model, pre_save, self._pre_save_receiver, sender=self.related_model) register_reciever(self.model, post_save, self._post_save_receiver, sender=self.related_model) register_reciever(self.model, post_save, self._post_save_receiver_for_creation) def unwatch(self): # unregister the receivers unregister_reciever(self.model, pre_save, self._pre_save_receiver) unregister_reciever(self.model, post_save, self._post_save_receiver) unregister_reciever(self.model, post_save, self._post_save_receiver_for_creation) def get_value(self, instance): try: return getattr(instance, self.related_attr, None) except ObjectDoesNotExist: return None def get_values(self, instance): value = self.get_value(instance) if value is None: return set() if hasattr(value, 'iterator'): value = value.iterator() elif not hasattr(value, '__iter__'): value = tuple([value]) return set(value) def _pre_save_receiver(self, sender, instance, **kwargs): if kwargs.get('row', False): # should not call any callback while it is called via fixtures or # so on return self._investigator.prepare(instance) def _post_save_receiver(self, sender, instance, **kwargs): if kwargs.get('row', False): # should not call any callback while it is called via fixtures or # so on return # get a reverse related objects from the instance instance_cached = self._investigator.get_cached(instance.pk) values_cached = self.get_values(instance_cached) values_latest = self.get_values(instance) object_set = values_cached | values_latest if any(self._investigator.investigate(instance)): for obj in object_set: self.call(obj) def _post_save_receiver_for_creation(self, sender, instance, created, **kwargs): if kwargs.get('row', False): # should not call any callback while it is called via fixtures or # so on return if self._call_on_created and created: self.call(instance)