diff --git a/savepointradio/core/behaviors.py b/savepointradio/core/behaviors.py index 72051d8..7322e54 100644 --- a/savepointradio/core/behaviors.py +++ b/savepointradio/core/behaviors.py @@ -21,13 +21,17 @@ class Disableable(models.Model): self.disabled = True self.disabled_date = timezone.now() self.disabled_reason = reason - self.save() + self.save(update_fields=['disabled', + 'disabled_date', + 'disabled_reason']) def enable(self): self.disabled = False self.disabled_date = None self.disabled_reason = '' - self.save() + self.save(update_fields=['disabled', + 'disabled_date', + 'disabled_reason']) def _is_enabled(self): return not self.disabled @@ -52,7 +56,7 @@ class Publishable(models.Model): if date is None: date = timezone.now() self.published_date = date - self.save() + self.save(update_fields=['published_date']) def _is_published(self): if self.published_date is not None: diff --git a/savepointradio/radio/apps.py b/savepointradio/radio/apps.py index 39319b6..23039e2 100644 --- a/savepointradio/radio/apps.py +++ b/savepointradio/radio/apps.py @@ -5,4 +5,4 @@ class RadioConfig(AppConfig): name = 'radio' def ready(self): - from .signals import update_sorted_fields + from .signals import cascade_disable, update_sorted_fields diff --git a/savepointradio/radio/models.py b/savepointradio/radio/models.py index 1151163..9c41962 100644 --- a/savepointradio/radio/models.py +++ b/savepointradio/radio/models.py @@ -142,7 +142,8 @@ class Song(Disableable, Publishable, Timestampable, models.Model): artists involved. """ if self.song_type == 'S': - all_artists = ', '.join([a.full_name for a in self.artists.all()]) + enabled_artists = self.artists.all().filter(disabled=False) + all_artists = ', '.join([a.full_name for a in enabled_artists]) return '{} - {} [{}]'.format(self.game.title, self.title, all_artists) diff --git a/savepointradio/radio/signals.py b/savepointradio/radio/signals.py index eaf7b58..3198d8f 100644 --- a/savepointradio/radio/signals.py +++ b/savepointradio/radio/signals.py @@ -1,5 +1,6 @@ -from django.db.models.signals import pre_save +from django.db.models.signals import post_save, pre_save from django.dispatch import receiver +from django.utils import timezone from core.utils import naturalize from .models import Album, Artist, Game, Song @@ -19,3 +20,71 @@ def update_sorted_fields(sender, instance, **kwargs): instance.sorted_full_name = naturalize(instance.full_name) else: instance.sorted_title = naturalize(instance.title) + + +@receiver(post_save, sender=Album) +@receiver(post_save, sender=Artist) +@receiver(post_save, sender=Game) +@receiver(post_save, sender=Song) +def cascade_disable(sender, instance, created, update_fields, **kwargs): + """ + If a radio object is disabled, be sure to update other objects that are + linked to it. + """ + if 'disabled' in update_fields: + if instance.disabled: + time = timezone.now() + if sender == Artist: + title = instance.full_name + else: + title = instance.title + reason = '{} "{}" was disabled.'.format(sender.__name__, title) + else: + time = None + reason = '' + + # The multiple _as_queryset's below are used to get around a + # potential infinite loop from the signal. Using .update() does not + # trigger it. + + # Disabling/Enabling an album does the same to all linked songs + if sender == Album: + album_songs = Song.objects.filter(album=instance) + album_songs.update(disabled=instance.disabled, + disabled_date=time, + disabled_reason=reason) + + # Disabling/Enabling an artist will only affect songs in which they + # are the only artist. + if sender == Artist: + for song in Song.objects.filter(artists=instance): + if song.artists.count() == 1: + song_as_queryset = Song.objects.filter(pk=song.pk) + song_as_queryset.update(disabled=instance.disabled, + disabled_date=time, + disabled_reason=reason) + + # Disabling/Enabling an game does the same to all linked songs + if sender == Game: + game_songs = Song.objects.filter(game=instance) + game_songs.update(disabled=instance.disabled, + disabled_date=time, + disabled_reason=reason) + + # Disabling a song does nothing, but enabling a song will enable all + # linked albums, artists, and games. + if sender == Song: + if not instance.disabled: + album_as_queryset = Album.objects.filter(pk=instance.album.pk) + album_as_queryset.update(disabled=instance.disabled, + disabled_date=time, + disabled_reason=reason) + + instance.artists.all().update(disabled=instance.disabled, + disabled_date=time, + disabled_reason=reason) + + game_as_queryset = Album.objects.filter(pk=instance.game.pk) + game_as_queryset.update(disabled=instance.disabled, + disabled_date=time, + disabled_reason=reason)