From 710a886a2f9e13b7efa8876882be90ade04ddd90 Mon Sep 17 00:00:00 2001 From: mathieu Date: Mon, 11 Jul 2016 11:31:54 +0200 Subject: [PATCH] Optimization of RealTimeCustomSIgnal Modify methods of Signal Add routers --- app/settings.py | 5 +- telemeta/search_indexes.py | 6 +- telemeta/util/search_router.py | 15 ++++ telemeta/util/search_signals.py | 120 +++++++++++++++++--------------- 4 files changed, 84 insertions(+), 62 deletions(-) create mode 100644 telemeta/util/search_router.py diff --git a/app/settings.py b/app/settings.py index 762764eb..88847ef6 100644 --- a/app/settings.py +++ b/app/settings.py @@ -330,8 +330,9 @@ HAYSTACK_CONNECTIONS = { }, } -HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' -# HAYSTACK_SIGNAL_PROCESSOR = 'telemeta.util.search_signals.RealTimeCustomSignal' +HAYSTACK_ROUTERS = ['telemeta.util.search_router.AutoRouter', 'haystack.routers.DefaultRouter'] +# HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' +HAYSTACK_SIGNAL_PROCESSOR = 'telemeta.util.search_signals.RealTimeCustomSignal' HAYSTACK_SEARCH_RESULTS_PER_PAGE = 50 BOWER_COMPONENTS_ROOT = '/srv/bower/' diff --git a/telemeta/search_indexes.py b/telemeta/search_indexes.py index d3aa0878..c4949789 100644 --- a/telemeta/search_indexes.py +++ b/telemeta/search_indexes.py @@ -248,8 +248,10 @@ class LocationIndex(indexes.SearchIndex, indexes.Indexable): return Location def index_queryset(self, using=None): - return MediaItem.objects.all().locations() - + loc = MediaItem.objects.values('location') + old = Location.objects.filter(current_location__in=loc).values('id') + anc = LocationRelation.objects.filter(location__in=loc).values('ancestor_location') + return Location.objects.filter(Q(pk__in=loc)|Q(pk__in=old)|Q(pk__in=anc)) class LocationAliasIndex(indexes.SearchIndex, indexes.Indexable): diff --git a/telemeta/util/search_router.py b/telemeta/util/search_router.py new file mode 100644 index 00000000..3f3f60f6 --- /dev/null +++ b/telemeta/util/search_router.py @@ -0,0 +1,15 @@ +from haystack.routers import BaseRouter +from telemeta.models.instrument import Instrument, InstrumentAlias +from telemeta.models.location import LocationAlias, Location + +#Router in order to determine +#that autocomplete data are stored in "autocomplete" index +class AutoRouter(BaseRouter): + + def for_write(self, **hints): + obj = hints.get('instance') + if isinstance(obj, Instrument) or isinstance(obj, InstrumentAlias) or isinstance(obj, Location) \ + or isinstance(obj, LocationAlias): + return 'autocomplete' + else: + return None \ No newline at end of file diff --git a/telemeta/util/search_signals.py b/telemeta/util/search_signals.py index cf96b3f2..f3710794 100644 --- a/telemeta/util/search_signals.py +++ b/telemeta/util/search_signals.py @@ -1,74 +1,78 @@ -from django.db import models -from haystack import signals from telemeta.models import * -from telemeta.search_indexes import * +from haystack import signals +from django.db.models.signals import post_save, post_delete, pre_delete from django.db.models import Q -#Custom realtime signal in order to update the "autcomplete" index +#Custom realtime signal in order to update the "autocomplete" index #when add/remove instruments/locations in items. #Differences of values of fields are checked by the tracker #of django-dirtyfields' module class RealTimeCustomSignal(signals.RealtimeSignalProcessor): - handleFields = ('location', 'instrument', 'alias') - handleModels = (MediaItem, MediaItemPerformance, ) + + sender_auto_only = (Instrument, InstrumentAlias, Location, LocationAlias) def __init__(self, *args, **kwargs): super(RealTimeCustomSignal, self).__init__(*args, **kwargs) - self.update_fields = [] - - def post_save_location(self, object): - id = object.get_dirty_fields(check_relationship=True).get('location') - locs = Location.objects.filter(Q(pk=id) | Q(past_names__pk=id) | Q(descendant_relations__location__pk=id)) - localias = LocationAlias.objects.filter(location__id=id) - for loc in locs: - LocationIndex().remove_object(instance=loc, using='autocomplete') - for loc in localias: - LocationAliasIndex().remove_object(instance=loc, using='autocomplete') - if object.location is not None: - locs = MediaItem.objects.filter(id=object.id).locations() - localias = LocationAlias.objects.filter(location__pk=object.location.id) - for loc in locs: - LocationIndex().update_object(instance=loc, using='autocomplete') - for loc in localias: - LocationAliasIndex().update_object(instance=loc, using='autocomplete') - - - def post_save_instrument(self, object): - id = object.get_dirty_fields(check_relationship=True).get('instrument') - if id is not None: - instru = Instrument.objects.get(pk=id) - InstrumentIndex().remove_object(instance=instru, using='autocomplete') - if object.instrument is not None: - newinstru = Instrument.objects.get(id=object.instrument.id) - InstrumentIndex().update_object(instance=newinstru, using='autocomplete') - def post_save_alias(self, object): - id = object.get_dirty_fields(check_relationship=True).get('alias') - if id is not None: - alias = InstrumentAlias.objects.get(pk=id) - InstrumentAliasIndex().remove_object(instance=alias, using='autocomplete') - if object.alias is not None: - newalias = InstrumentAlias.objects.get(id=object.alias.id) - InstrumentAliasIndex().update_object(instance=newalias, using='autocomplete') + def update_instrument(self, instance, old_value): + if instance is not None and instance.instrument is not None: + post_save.send(sender=Instrument, instance=instance.instrument, in_real_signal=True) + if old_value is not None: + instru = Instrument.objects.get(id=old_value) if not isinstance(old_value, Instrument) else old_value + nb = instru.performances.count() + if nb == 0: + post_delete.send(sender=Instrument, instance=instru) - def handle_pre_save(self, sender, instance, **kwargs): - if sender in self.handleModels and instance.is_dirty(check_relationship=True): - for field in instance.get_dirty_fields(check_relationship=True).keys(): - if field in self.handleFields: - self.update_fields.append(field) + def update_alias(self, instance, old_value): + if instance is not None and instance.alias is not None: + post_save.send(sender=InstrumentAlias, instance=instance.alias, in_real_signal=True) + if old_value is not None: + alias = InstrumentAlias.objects.get(id=old_value) if not isinstance(old_value, InstrumentAlias) else old_value + nb = alias.performances.count() + if nb == 0: + post_delete.send(sender=InstrumentAlias, instance=alias) - def handle_pre_delete(self, sender, instance, **kwargs): - InstrumentIndex().remove_object(instance=instance.instrument, using='autocomplete') - InstrumentAliasIndex().remove_object(instance=instance.alias, using='autocomplete') + def update_location(self, instance, old_value): + if instance is not None and instance.location is not None: + loc = Location.objects.filter(Q(current_location=instance.location)|Q(descendant_relations__location=instance.location)) + localias = LocationAlias.objects.filter(location=instance.location) + post_save.send(sender=Location, instance=instance.location, in_real_signal=True) + for l in loc: + post_save.send(sender=Location, instance=l, in_real_signal=True) + for l in localias: + post_save.send(sender=LocationAlias, instance=l, in_real_signal=True) + if old_value is not None: + location = Location.objects.get(id=old_value) if not isinstance(old_value, Location) else old_value + loc = Location.objects.filter(Q(current_location=location) | Q(descendant_relations__location=location)) + can_delete_alias = post_delete.send(sender=Location, instance=location, in_real_signal=True)[0][1] + for l in loc: + post_delete.send(sender=Location, instance=l, in_real_signal=True) + if can_delete_alias: + localias = LocationAlias.objects.filter(location=location) + for l in localias: + post_delete.send(sender=LocationAlias, instance=l, in_real_signal=True) def handle_save(self, sender, instance, **kwargs): - if sender in self.handleModels: - for field in self.update_fields: - getattr(self, "post_save_%s" % field)(instance) - del self.update_fields[:] - super(RealTimeCustomSignal, self).handle_save(sender, instance, **kwargs) + if sender == MediaItemPerformance or sender == MediaItem: + df = instance.get_dirty_fields(check_relationship=True) + if df.has_key('instrument'): + self.update_instrument(instance, df.get('instrument')) + if df.has_key('alias'): + self.update_alias(instance, df.get('alias')) + if df.has_key('location'): + self.update_location(instance, df.get('location')) + if kwargs.get('in_real_signal', False) or sender not in self.sender_auto_only: + super(RealTimeCustomSignal, self).handle_save(sender, instance, **kwargs) - def setup(self): - super(RealTimeCustomSignal, self).setup() - models.signals.pre_save.connect(self.handle_pre_save) - models.signals.pre_delete.connect(self.handle_pre_delete, sender=MediaItemPerformance) + def handle_delete(self, sender, instance, **kwargs): + if sender == MediaItemPerformance: + self.update_instrument(instance=None, old_value=instance.instrument) + self.update_alias(instance=None, old_value=instance.alias) + elif sender == MediaItem: + self.update_location(instance=None, old_value=instance.location) + elif sender == Location: + l = Location.objects.filter(Q(past_names=instance)|Q(ancestor_relations__ancestor_location=instance)|Q(id=instance.id)) + if l.count() != 0 and l.filter(mediaitem__isnull=False).exists(): + return False + super(RealTimeCustomSignal, self).handle_delete(sender=sender, instance=instance, **kwargs) + return True \ No newline at end of file -- 2.39.5