class Ensemble(models.Model, Mergeable): name = models.CharField(max_length=150) nationality = models.ForeignKey( 'common.Nationality', blank=True, null=True, related_name='ensembles', ) slug = MySlugField('name') class Meta: ordering = ('name',) def __unicode__(self): return self.name @models.permalink def get_absolute_url(self): return 'classical:ensemble', (self.slug,) def performances_by_composer(self): # FIXME: Move to manager return self.performances.order_by( 'recording__work__composer', 'recording__work__sort_value', )
class Ensemble(models.Model, Mergeable): name = models.CharField(max_length=150) nationality = models.ForeignKey(Nationality, blank=True, null=True, related_name='ensembles') slug = MySlugField('name') class Meta: ordering = ('name', ) def __unicode__(self): return self.name @models.permalink def get_absolute_url(self): return ('classical-ensemble', (self.slug, )) def performances_by_composer(self): return self.performances.order_by( 'recording__work__composer', 'recording__work__sort_value', ) def dirty_tags(self): MusicFile.objects.filter( movement__recording__performances__ensembleperformance__ensemble= self, ).update(tags_dirty=True)
class Recording(models.Model): work = models.ForeignKey(Work, related_name='recordings') year = models.IntegerField(blank=True, null=True) slug = MySlugField('slug_name', filter='slug_filter') created = models.DateTimeField( default=datetime.datetime.utcnow, null=True, blank=True, ) objects = RecordingManager() def __unicode__(self): ret = u"%s" % self.work if self.year: ret += u" (%d)" % self.year return ret def delete(self, *args, **kwargs): for track in self.get_tracks(): track.delete() super(Recording, self).delete(*args, **kwargs) def get_absolute_url(self): return '%s#%s' % (self.work.get_absolute_url(), self.slug) def short_name(self): return ", ".join( x.get_subclass().short_name() for x in self.performances.all() ) def slug_name(self): ret = unicode(self.short_name()) if self.year: ret += " %d" % self.year return ret def slug_filter(self): # FIXME: Move to manager return type(self).objects.filter(work=self.work) def get_tracks(self): return MusicFile.objects.filter( movement__recording=self, ).order_by('movement__num')
class Recording(models.Model): work = models.ForeignKey(Work, related_name='recordings') year = models.IntegerField(blank=True, null=True) slug = MySlugField('slug_name', filter='slug_filter') def __unicode__(self): ret = u"%s" % self.work if self.year: ret += u" (%d)" % self.year return ret def delete(self, *args, **kwargs): for track in self.get_tracks(): track.delete() super(Recording, self).delete(*args, **kwargs) def get_absolute_url(self): return "%s#%s" % (self.work.get_absolute_url(), self.slug) def short_name(self): return ", ".join( [x.get_subclass().short_name() for x in self.performances.all()]) def slug_name(self): ret = unicode(self.short_name()) if self.year: ret += " %d" % self.year return ret def slug_filter(self): return type(self).objects.filter(work=self.work) def get_tracks(self): return MusicFile.objects.filter( movement__recording=self).order_by('movement') def total_duration(self): return sum(self.get_tracks().values_list('length', flat=True)) def dirty_tags(self): self.get_tracks().update(tags_dirty=True)
class Category(TreeNode): name = models.CharField(max_length=100) long_name = models.CharField(max_length=100, unique=True) slug = MySlugField('long_name') class Meta: ordering = ('path', ) verbose_name_plural = 'Categories' def __unicode__(self): return self.long_name @models.permalink def get_absolute_url(self): return ('classical-category', (self.slug, )) def works_by_composer(self): return self.works.order_by('composer', 'sort_value')
class Author(models.Model): last_name = models.CharField(max_length=100) first_names = models.CharField(max_length=100) slug = MySlugField('long_name') last_name_first = FirstLetterField('last_name') objects = AuthorManager() class Meta: ordering = ('last_name', 'first_names') def __unicode__(self): return u"%s, %s" % (self.last_name, self.first_names) @models.permalink def get_absolute_url(self): return 'books:author', (self.slug, ) def long_name(self): return "%s %s" % (self.first_names, self.last_name)
class Artist(models.Model, NextPreviousMixin): name = models.CharField(max_length=250) # Artist represents a single person is_solo_artist = models.BooleanField(default=False) url = models.CharField(max_length=200, blank=True) slug = MySlugField('slug_name') name_first = FirstLetterField('name') nationality = models.ForeignKey( 'common.Nationality', null=True, blank=True, related_name='albums_artists', ) objects = ArtistManager() class Meta: ordering = ('name', ) def __unicode__(self): return u"%s" % self.name @models.permalink def get_absolute_url(self): return 'albums:artist', (self.slug, ) def long_name(self): if not self.is_solo_artist: return self.name try: last, first = self.name.split(', ', 1) return "%s %s" % (first, last) except ValueError: return self.name slug_name = long_name
class Work(models.Model, Mergeable, NextPreviousMixin): title = models.CharField(max_length=200) nickname = models.CharField(max_length=200, blank=True) composer = models.ForeignKey(Artist, related_name='works') year = models.IntegerField('Year of composition', blank=True, null=True) year_question = models.BooleanField( 'Year of composition is uncertain', default=False, ) key = models.ForeignKey('Key', null=True, blank=True, related_name='works') category = models.ForeignKey('Category', null=True, blank=True, related_name='works') slug = MySlugField('slug_name', filter='slug_filter') sort_value = DenormalisedCharField('get_sort_value') objects = WorkManager() class Meta: ordering = ('sort_value', ) def __unicode__(self): return self.pretty_title() @models.permalink def get_absolute_url(self): return ('classical-work', (self.composer.slug, self.slug)) def next(self): return super(Work, self).next(composer=self.composer) def previous(self): return super(Work, self).previous(composer=self.composer) def pretty_title(self, show_year=True): extras = [ ('key', u" in %s"), ('nickname', u" «%s»"), ] ret = self.title for attr, format in extras: if getattr(self, attr): ret += format % getattr(self, attr) if self.catalogues.count(): ret += u", %s" % ", ".join([str(x) for x in self.catalogues.all()]) if show_year and self.year: ret += " (%d%s)" % (self.year, self.year_question and '?' or '') return ret def slug_name(self): return self.pretty_title(show_year=False) short_name = slug_name def slug_filter(self): return type(self).objects.filter(composer=self.composer) def get_sort_value(self): val = '' def zeropad(match): return "%04d" % int(match.group(0)) for cat in self.catalogues.all(): val += "%02d%s" % (cat.catalogue.num, \ re.sub('\d+', zeropad, cat.value)) val += re.sub('\d+', zeropad, self.title) val += self.nickname return val def dirty_tags(self): MusicFile.objects.filter(movement__recording__work=self).update( tags_dirty=True)
class Album(models.Model, NextPreviousMixin): title = models.CharField(max_length=200) artist = models.ForeignKey(Artist, related_name='albums') year = models.IntegerField(blank=True, null=True) image = YADTImageField(variants={ 'large': { 'format': 'jpeg', 'pipeline': ({ 'name': 'crop', 'width': 300, 'height': 300 }, ), }, 'thumbnail': { 'format': 'jpeg', 'pipeline': ({ 'name': 'crop', 'width': 125, 'height': 125 }, ), }, }, cachebust=True, track_exists=True) slug = MySlugField('title') created = models.DateTimeField( null=True, default=datetime.datetime.utcnow, ) class Meta: ordering = ('year', 'title') def __unicode__(self): if self.year: return u"%s (%d)" % (self.title, self.year) return u"%s" % self.title def delete(self, *args, **kwargs): for track in self.get_tracks(): track.delete() super(Album, self).delete(*args, **kwargs) @models.permalink def get_absolute_url(self): return 'albums:album', (self.artist.slug, self.slug) def get_tracks(self): return MusicFile.objects.filter(track__cd__album=self, ).order_by( 'track__cd', 'track__num', ) def total_duration(self): return self.get_tracks().aggregate( models.Sum('length'), ).values()[0] or 0 def next(self): return super(Album, self).next(artist_id=self.artist_id) def previous(self): return super(Album, self).previous(artist_id=self.artist_id)
class Artist(models.Model, NextPreviousMixin): surname = models.CharField(max_length=100) forenames = models.CharField(max_length=100, blank=True) original_surname = models.CharField(max_length=100, blank=True) original_forenames = models.CharField(max_length=100, blank=True) slug = MySlugField('slug_name') url = models.CharField(max_length=200, blank=True) born = models.IntegerField(blank=True, null=True) died = models.IntegerField(blank=True, null=True) born_question = models.BooleanField( "Year of birth uncertain", default=False, ) died_question = models.BooleanField( 'Year of death uncertain', default=False, ) nationality = models.ForeignKey( 'common.Nationality', blank=True, null=True, related_name='classical_artists', ) image = YADTImageField(variants={ 'large': { 'format': 'jpeg', }, }, cachebust=True, track_exists=True) objects = ArtistManager() class Meta: ordering = ('surname', 'forenames', 'born') def __unicode__(self): if self.forenames: name = "%s, %s" % (self.surname, self.forenames) else: name = self.surname if self.born or self.died: name += " (%s)" % self.date_range() return name @models.permalink def get_absolute_url(self): return 'classical:artist', (self.slug,) def next_composer(self): return super(Artist, self).next(works__isnull=False) def previous_composer(self): return super(Artist, self).previous(works__isnull=False) def slug_name(self): if self.forenames: return "%s %s" % (self.forenames, self.surname) return self.surname short_name = slug_name def long_name(self): name = self.short_name() if self.original_surname or self.original_forenames: name += " (%s %s)" % ( self.original_forenames, self.original_surname, ) if self.born or self.died: name += " (%s)" % self.date_range() return name def date_range(self): born = "" if self.born: born = "%d%s" % (self.born, self.born_question and '?' or '') died = "" if self.died: died = "%d%s" % (self.died, self.died_question and '?' or '') return "%s-%s" % (born, died) def performances_by_composer(self): # FIXME: Move to manager return self.performances.order_by( 'recording__work__composer', 'recording__work__sort_value', ) def instruments(self): return Instrument.objects.filter( performances__artist=self, ).distinct() def biography(self): items = [] if self.works.exists(): items.append('composer') items.extend(self.instruments().values_list('adjective', flat=True)) if self.nationality: nationality = u"%s " % self.nationality.adjective else: nationality = "" if len(items) > 1: last = items.pop() res = "%s%s and %s" % (nationality, ", ".join(items), last) else: res = "%s%s" % (nationality, items[0]) return res.capitalize()
class AbstractArtist(models.Model): slug = MySlugField('slug_name') url = models.CharField(max_length=200, blank=True) class Meta: abstract = True
class Album(models.Model, NextPreviousMixin): title = models.CharField(max_length=200) artist = models.ForeignKey(Artist, related_name='albums') year = models.IntegerField(blank=True, null=True) cover = StdImageField(upload_to='album_covers', size=(300, 300), thumbnail_size=(125, 125), blank=True) slug = MySlugField('title') dir_name = DirNameField('get_dir_name') objects = AlbumManager() class Meta: ordering = ('year', 'title') def __unicode__(self): if self.year: return u"%s (%d)" % (self.title, self.year) return self.title def delete(self, *args, **kwargs): for track in self.get_tracks(): track.delete() super(Album, self).delete(*args, **kwargs) @models.permalink def get_absolute_url(self): return ('nonclassical-album', (self.artist.slug, self.slug)) def get_dir_name(self): if self.year: return "%d %s" % (self.year, self.title) return self.title def get_tracks(self): return MusicFile.objects.filter(track__cd__album=self). \ order_by('track__cd', 'track') def get_nonclassical_tracks(self): return Track.objects.filter(cd__album=self). \ order_by('cd__num', 'track') def total_duration(self): return self.get_tracks().aggregate(Sum('length')).values()[0] or 0 def next(self): return super(Album, self).next(artist=self.artist) def previous(self): return super(Album, self).previous(artist=self.artist) def set_artwork_from_url(self, url): tempfile, headers = urllib.urlretrieve(url) try: self.cover = DjangoFile(open(tempfile)) self.save() except: self.cover.delete() raise finally: try: os.unlink(tempfile) except: pass