def html(self, tags=True, pretty_title=False): url = None if not tags else self.get_absolute_url() conservation = hlp(self.lieu_conservation, ugettext('Lieu de conservation'), tags) if self.ancrage.date or self.ancrage.date_approx: ancrage = hlp(self.ancrage.html(tags, caps=False), ugettext('date')) else: ancrage = None if self.cote: conservation += f", {hlp(self.cote, 'cote', tags)}" if self.titre: l = [cite(self.titre, tags)] if self.numero: l.append(self.no()) if ancrage is not None: l.append(ancrage) if self.folio: l.append(hlp(self.f(), ugettext('folio'), tags)) if self.page: l.append(hlp(self.p(), ugettext('page'), tags)) if self.lieu_conservation: l[-1] += f' ({conservation})' else: l = [conservation] if ancrage is not None: l.append(ancrage) l = (l[0], small(str_list(l[1:]), tags=tags)) if pretty_title else l out = str_list(l) return mark_safe(href(url, out, tags))
def caracteristiques_iterator(self, tags=False): if self.numero: yield ugettext('n° %s') % self.numero if self.coupe: yield hlp(ugettext('en %s') % self.coupe, ugettext('coupe'), tags) if self.incipit: yield hlp(ugettext('« %s »') % self.incipit, ugettext('incipit'), tags) # On ajoute uniquement le tempo s’il n’y a pas besoin de lui dans le # titre non significatif, c’est-à-dire s’il y a déjà un genre. if self.tempo and self.genre_id is not None: yield hlp(self.tempo, ugettext('Tempo'), tags) if self.tonalite: gamme, note, alteration = self.tonalite gamme = GAMMES.get(gamme, '') note = self.NOTES[note] alteration = self.ALTERATIONS[alteration] tonalite = ugettext('en %s') % str_list( (em(note, tags), alteration, gamme), ' ') yield tonalite if self.sujet: yield hlp(ugettext('sur %s') % self.sujet, ugettext('sujet'), tags) if self.arrangement is not None: yield f'({self.get_arrangement_display()})' if self.surnom: yield hlp(f'({self.surnom})', ugettext('surnom'), tags) if self.nom_courant: yield hlp(self.nom_courant, ugettext('nom courant'), tags) if self.opus: yield hlp(ugettext('op. %s') % self.opus, ugettext('opus'), tags) if self.ict: yield hlp(self.ict, ugettext('Indice de Catalogue Thématique'), tags)
def html(self, tags=True, auteurs=True, titre=True, descr=True, ancestors=True, ancestors_links=False, links=True, show_type_extrait=True): l = [] if auteurs: l.append(self.auteurs_html(tags=tags)) if titre: if ancestors: l.append(self.get_referent_ancestors_html( tags=tags, links=ancestors_links)) if self.has_titre_significatif(): titre_complet = cite(self.get_titre_significatif(), tags=tags) else: titre_complet = self.get_titre_non_significatif( tags=tags, caps=(self.type_extrait is None or self.type_extrait in self.TYPES_EXTRAIT_CACHES)) extrait = capfirst(self.get_extrait(show_type=show_type_extrait)) if extrait: if titre_complet: titre_complet = f'{extrait} {titre_complet}' elif self.type_extrait not in self.TYPES_EXTRAIT_CACHES: titre_complet = extrait url = None if not tags else self.get_absolute_url() l.append(href(url, titre_complet, tags & links)) if descr: l.append(self.get_description(tags=tags)) return mark_safe(str_list(l))
def caracteristiques_iterator(self, tags=False): if self.numero: yield ugettext('n° %s') % self.numero if self.coupe: yield hlp(ugettext('en %s') % self.coupe, ugettext('coupe'), tags) if self.incipit: yield hlp( ugettext('« %s »') % self.incipit, ugettext('incipit'), tags) # On ajoute uniquement le tempo s’il n’y a pas besoin de lui dans le # titre non significatif, c’est-à-dire s’il y a déjà un genre. if self.tempo and self.genre_id is not None: yield hlp(self.tempo, ugettext('Tempo'), tags) if self.tonalite: gamme, note, alteration = self.tonalite gamme = GAMMES.get(gamme, '') note = self.NOTES[note] alteration = self.ALTERATIONS[alteration] tonalite = ugettext('en %s') % str_list( (em(note, tags), alteration, gamme), ' ') yield tonalite if self.sujet: yield hlp(ugettext('sur %s') % self.sujet, ugettext('sujet'), tags) if self.arrangement is not None: yield f'({self.get_arrangement_display()})' if self.surnom: yield hlp(f'({self.surnom})', ugettext('surnom'), tags) if self.nom_courant: yield hlp(self.nom_courant, ugettext('nom courant'), tags) if self.opus: yield hlp(ugettext('op. %s') % self.opus, ugettext('opus'), tags) if self.ict: yield hlp(self.ict, ugettext('Indice de Catalogue Thématique'), tags)
def standard(main, prenoms): particule = self.get_particule(naissance=(designation == 'B'), lon=lon) l = [] if nom and not prenoms: l.append(titre) l.append(main) if show_prenoms and (prenoms or particule and not lon): if lon: l.insert(max(len(l) - 1, 0), prenoms) else: if prenoms: prenoms = abbreviate(prenoms, tags=tags, enabled=abbr) if particule: particule = sc(particule, tags) prenom_and_particule = (f'{prenoms} {particule}' if prenoms and particule else (prenoms or particule)) l.append(f'({prenom_and_particule})') out = str_list(l, ' ') if pseudonyme: alias = (ugettext('dite') if self.is_feminin() else ugettext('dit')) out += f' {alias}\u00A0{pseudonyme}' return out
def html(self, tags=True, auteurs=True, titre=True, descr=True, ancestors=True, ancestors_links=False, links=True, show_type_extrait=True): l = [] if auteurs: l.append(self.auteurs_html(tags=tags)) if titre: if ancestors: l.append( self.get_referent_ancestors_html(tags=tags, links=ancestors_links)) if self.has_titre_significatif(): titre_complet = cite(self.get_titre_significatif(), tags=tags) else: titre_complet = self.get_titre_non_significatif( tags=tags, caps=(self.type_extrait is None or self.type_extrait in self.TYPES_EXTRAIT_CACHES)) extrait = capfirst(self.get_extrait(show_type=show_type_extrait)) if extrait: if titre_complet: titre_complet = f'{extrait} {titre_complet}' elif self.type_extrait not in self.TYPES_EXTRAIT_CACHES: titre_complet = extrait url = None if not tags else self.get_absolute_url() l.append(href(url, titre_complet, tags & links)) if descr: l.append(self.get_description(tags=tags)) return mark_safe(str_list(l))
def get_description(self, tags=True): l = [] if self.has_titre_significatif(): l.append(self.get_titre_non_significatif(tags=tags)) caracteristiques = list(self.caracteristiques_iterator(tags=tags)) if self.has_titre_non_significatif(): # La première caractéristique est utilisée dans le titre non # significatif. caracteristiques = caracteristiques[1:] l.extend(caracteristiques) return str_list(l, infix=' ')
def moment_str(self, tags=True, short=False): l = [] date = self.date_str(tags, short) heure = self.heure_str() pat_date = (ugettext('%(date)s') if self.has_date and self.date else ugettext('%(date)s')) pat_heure = (ugettext('à %(heure)s') if self.has_heure and self.heure else ugettext('%(heure)s')) l.append(pat_date % {'date': date}) l.append(pat_heure % {'heure': heure}) return str_list(l, ' ')
def get_titre_non_significatif(self, tags=True, caps=False): if not self.has_titre_non_significatif(): return '' if self.genre is None: assert self.tempo != '' l = [capfirst(self.tempo) if caps else self.tempo] else: l = [capfirst(self.genre.nom) if caps else self.genre.nom] if not self.has_titre_significatif(): l.append(self.get_pupitres_str(tags=False, solistes=True)) l.append(next(self.caracteristiques_iterator(tags=tags), None)) return str_list(l, infix=' ')
def html(self, tags=True): relache = '' circonstance = '' if self.circonstance: circonstance = hlp(self.circonstance, ugettext('circonstance'), tags) if self.relache: relache = microdata(ugettext('Relâche'), 'eventType', tags=tags) lieu = microdata(self.debut.lieu_str(tags), 'location', tags=tags) return mark_safe( str_list((lieu, circonstance, self.debut.heure_str(), relache)))
def html(self, tags=True, pretty_title=False, link=True): url = None if not tags else self.get_absolute_url() conservation = hlp(self.lieu_conservation, ugettext('Lieu de conservation'), tags) if self.ancrage.date or self.ancrage.date_approx: ancrage = hlp(self.ancrage.html(tags, caps=False), ugettext('date')) else: ancrage = None if self.cote: conservation += f", {hlp(self.cote, 'cote', tags)}" if self.titre: l = [cite(self.titre, tags)] if self.numero: l.append(self.no()) if ancrage is not None: l.append(ancrage) if self.lieu_conservation: l[-1] += f' ({conservation})' else: l = [conservation] if ancrage is not None: l.append(ancrage) if self.folio: l.append(hlp(self.f(), ugettext('folio'), tags)) if self.page: l.append(hlp(self.p(), ugettext('page'), tags)) if self.parent is not None: l.insert( 0, self.parent.html(tags=tags, pretty_title=pretty_title, link=pretty_title)) l = (l[0], small(str_list(l[1:]), tags=tags)) if pretty_title else l out = str_list(l) if link: return mark_safe(href(url, out, tags)) return out
def html(self, tags=True): relache = '' circonstance = '' if self.circonstance: circonstance = hlp(self.circonstance, ugettext('circonstance'), tags) if self.relache: relache = microdata(ugettext('Relâche'), 'eventType', tags=tags) lieu = microdata(self.debut.lieu_str(tags), 'location', tags=tags) return mark_safe(str_list((lieu, circonstance, self.debut.heure_str(), relache)))
def html(self, tags=True, caps=False): l = [] first = True for c in self: valeur = c.valeur if first and caps: valeur = capfirst(valeur) first = False valeur = mark_safe(valeur) if c.type: l.append(hlp(valeur, c.type, tags=tags)) else: l.append(valeur) return mark_safe(str_list(l))
def html(self, tags=True, short=False, caps=True): out = str_list((self.lieu_str(tags, short), self.moment_str(tags, short))) if caps: return capfirst(out) return out
def interpretes_html(self): return str_list([i.html() for i in self.interpretes()])
class Oeuvre(TreeModelMixin, AutoriteModel, UniqueSlugModel): prefixe_titre = CharField(_('article'), max_length=20, blank=True) titre = CharField(_('titre'), max_length=200, blank=True, db_index=True) coordination = CharField(_('coordination'), max_length=20, blank=True, db_index=True) prefixe_titre_secondaire = CharField(_('article'), max_length=20, blank=True) titre_secondaire = CharField(_('titre secondaire'), max_length=200, blank=True, db_index=True) genre = ForeignKey('GenreDOeuvre', related_name='oeuvres', blank=True, null=True, verbose_name=_('genre'), on_delete=PROTECT) numero = NumberCharField( _('numéro'), max_length=10, blank=True, db_index=True, validators=[ RegexValidator( r'^[\d\w\-]+$', _('Vous ne pouvez saisir que des chiffres, ' 'lettres non accentuées et tiret, ' 'le tout sans espace.')) ], help_text=_( 'Exemple : « 5 » pour symphonie n° 5, « 7a » pour valse n° 7 a, ' 'ou encore « 3-7 » pour sonates n° 3 à 7. ' '<strong>Ne pas confondre avec le sous-numéro d’opus.</strong>')) coupe = CharField( _('coupe'), max_length=100, blank=True, db_index=True, validators=[ RegexValidator( r'^\D+$', _('Vous devez saisir les quantités ' 'en toutes lettres.')) ], help_text=_('Exemple : « trois actes » pour un opéra en trois actes.')) indeterminee = BooleanField( _('indéterminée'), default=False, help_text=_( 'Cocher si l’œuvre n’est pas identifiable, par exemple ' 'un quatuor de Haydn, sans savoir lequel. ' '<strong>Ne pas utiliser pour un extrait indéterminé</strong>, ' 'sélectionner plutôt dans le programme l’œuvre dont il est tiré ' 'et joindre une caractéristique le décrivant ' '(« un air », « un mouvement », etc.).')) incipit = CharField( _('incipit'), max_length=100, blank=True, db_index=True, help_text=_('Exemple : « Belle nuit, ô nuit d’amour » pour le n° 13 ' 'de l’acte III des <em>Contes d’Hoffmann</em> ' 'd’Offenbach.')) tempo = CharField( _('tempo'), max_length=50, blank=True, db_index=True, help_text=_('Exemple : « Largo », « Presto ma non troppo », etc. ' 'Ne pas saisir d’indication métronomique.')) NOTES = NOTES ALTERATIONS = ALTERATIONS GAMMES = GAMMES TONALITES = [(f'{gamme_k}{note_k}{alter_k}', _(str_list((note_v, alter_v, gamme_v), ' '))) for gamme_k, gamme_v in GAMMES.items() for note_k, note_v in NOTES.items() for alter_k, alter_v in ALTERATIONS.items()] tonalite = CharField(_('tonalité'), max_length=3, choices=TONALITES, blank=True, db_index=True) sujet = CharField( _('sujet'), max_length=80, blank=True, help_text=_( 'Exemple : « un thème de Beethoven » pour une variation sur un ' 'thème de Beethoven, « des motifs de ' '<em>Lucia di Lammermoor</em> » pour une fantaisie ' 'sur des motifs de <em>Lucia di Lammermoor</em> ' '(<em> et </em> sont les balises HTML ' 'pour mettre en emphase).')) TRANSCRIPTION = 1 ORCHESTRATION = 2 ARRANGEMENTS = ((TRANSCRIPTION, _('transcription')), (ORCHESTRATION, _('orchestration'))) arrangement = PositiveSmallIntegerField(_('arrangement'), choices=ARRANGEMENTS, blank=True, null=True, db_index=True) surnom = CharField(_('surnom'), max_length=50, blank=True, db_index=True, help_text=_( 'Exemple : « Jupiter » pour la symphonie n° 41 ' 'de Mozart.')) nom_courant = CharField( _('nom courant'), max_length=70, blank=True, db_index=True, help_text=_('Exemple : « barcarolle » pour le n° 13 de l’acte III des ' '<em>Contes d’Hoffmann</em> d’Offenbach.')) opus = CharField( _('opus'), max_length=6, blank=True, db_index=True, validators=[ RegexValidator( r'^[\d\w\-/]+$', _('Vous ne pouvez saisir que des chiffres, ' 'lettres non accentuées, tiret ' 'et barre oblique, le tout sans espace.')) ], help_text=_('Exemple : « 12 » pour op. 12, « 27/3 » pour op. 27 n° 3, ' '« 8b » pour op. 8 b, ou encore « 12-15 » ' 'pour op. 12 à 15.')) ict = CharField(_('ICT'), max_length=25, blank=True, db_index=True, help_text=_( 'Indice de Catalogue Thématique. Exemple : « RV 42 », ' '« K. 299d » ou encore « Hob. XVI:24 ».')) CREATION_TYPES = ( (1, _('genèse (composition, écriture, etc.)')), (2, _('première mondiale')), (3, _('première édition')), ) creation_type = PositiveSmallIntegerField(_('type de création'), choices=CREATION_TYPES, null=True, blank=True) creation = AncrageSpatioTemporel(verbose_name=_('création')) ORDERING = ('type_extrait', 'numero_extrait', 'titre', 'genre', 'numero', 'coupe', 'incipit', 'tempo', 'tonalite', 'sujet', 'arrangement', 'surnom', 'nom_courant', 'opus', 'ict') extrait_de = ForeignKey('self', null=True, blank=True, related_name='enfants', verbose_name=_('extrait de'), on_delete=CASCADE) path = PathField(order_by=ORDERING, db_index=True) ACTE = 1 TABLEAU = 2 SCENE = 3 MORCEAU = 4 PARTIE = 5 LIVRE = 6 ALBUM = 7 VOLUME = 8 CAHIER = 9 ORDRE = 10 MOUVEMENT = 11 PIECE = 12 SERIE = 13 TYPES_EXTRAIT_ROMAINS = (ACTE, LIVRE, ORDRE) TYPES_EXTRAIT_CACHES = (MORCEAU, MOUVEMENT, PIECE) TYPES_EXTRAIT = ( (ACTE, _('acte')), (TABLEAU, _('tableau')), (SCENE, _('scène')), (MORCEAU, _('morceau chanté')), (PARTIE, _('partie')), (LIVRE, _('livre')), (ALBUM, _('album')), (VOLUME, _('volume')), (CAHIER, _('cahier')), (ORDRE, _('ordre')), (MOUVEMENT, _('mouvement')), (PIECE, _('pièce de recueil')), (SERIE, _('série')), ) type_extrait = PositiveSmallIntegerField(_('type d’extrait'), choices=TYPES_EXTRAIT, blank=True, null=True, db_index=True) NUMERO_EXTRAIT_PATTERN = r'^([1-9]\d*)([^\d\.\-]*)$' NUMERO_EXTRAIT_RE = re.compile(NUMERO_EXTRAIT_PATTERN) numero_extrait = NumberCharField( _('numéro d’extrait'), max_length=10, blank=True, db_index=True, help_text=_( 'Le numéro de l’extrait au sein de l’œuvre, par exemple « 3 » ' 'pour le 3<sup>e</sup> mouvement d’un concerto, « 4 » pour ' 'l’acte IV d’un opéra, ou encore « 12b ».'), validators=[ RegexValidator( NUMERO_EXTRAIT_PATTERN, _('Vous devez saisir un nombre en chiffres arabes ' 'éventellement suivi de lettres.')) ]) filles = ManyToManyField('self', through='ParenteDOeuvres', related_name='meres', symmetrical=False, blank=True, verbose_name=_('filles')) objects = OeuvreManager() class Meta(object): verbose_name = _('œuvre') verbose_name_plural = _('œuvres') ordering = ('path', ) permissions = (('can_change_status', _('Peut changer l’état')), ) @staticmethod def invalidated_relations_when_saved(all_relations=False): relations = ( 'enfants', 'elements_de_programme', ) if all_relations: relations += ( 'dossiers', 'filles', ) return relations @permalink def get_absolute_url(self): return 'oeuvre_detail', [self.slug] @permalink def permalien(self): return 'oeuvre_permanent_detail', [self.pk] def link(self): return self.html(tags=True, auteurs=False, titre=True, descr=True, ancestors=True) link.short_description = _('lien') link.allow_tags = True def get_extrait(self, show_type=True): if not self.type_extrait or not self.numero_extrait: return '' match = self.NUMERO_EXTRAIT_RE.match(self.numero_extrait) if match is None: return '' digits, suffix = match.groups() if self.type_extrait in self.TYPES_EXTRAIT_ROMAINS: digits = to_roman(int(digits)) out = f'{digits}{suffix}' if self.type_extrait == self.MORCEAU: out = ugettext('№ ') + out elif self.type_extrait in (self.MOUVEMENT, self.PIECE): out += '.' elif show_type: return f'{self.get_type_extrait_display()} {out}' return out def caracteristiques_iterator(self, tags=False): if self.numero: yield ugettext('n° %s') % self.numero if self.coupe: yield hlp(ugettext('en %s') % self.coupe, ugettext('coupe'), tags) if self.incipit: yield hlp( ugettext('« %s »') % self.incipit, ugettext('incipit'), tags) # On ajoute uniquement le tempo s’il n’y a pas besoin de lui dans le # titre non significatif, c’est-à-dire s’il y a déjà un genre. if self.tempo and self.genre_id is not None: yield hlp(self.tempo, ugettext('Tempo'), tags) if self.tonalite: gamme, note, alteration = self.tonalite gamme = GAMMES.get(gamme, '') note = self.NOTES[note] alteration = self.ALTERATIONS[alteration] tonalite = ugettext('en %s') % str_list( (em(note, tags), alteration, gamme), ' ') yield tonalite if self.sujet: yield hlp(ugettext('sur %s') % self.sujet, ugettext('sujet'), tags) if self.arrangement is not None: yield f'({self.get_arrangement_display()})' if self.surnom: yield hlp(f'({self.surnom})', ugettext('surnom'), tags) if self.nom_courant: yield hlp(self.nom_courant, ugettext('nom courant'), tags) if self.opus: yield hlp(ugettext('op. %s') % self.opus, ugettext('opus'), tags) if self.ict: yield hlp(self.ict, ugettext('Indice de Catalogue Thématique'), tags) def caracteristiques_html(self, tags=True): return ' '.join(list(self.caracteristiques_iterator(tags=tags))) caracteristiques_html.allow_tags = True caracteristiques_html.short_description = _('caractéristiques') def get_pupitres_str(self, prefix=True, tags=False, solistes=False): if not self.pk: return '' pupitres = self.pupitres.all() if solistes: pupitres = [p for p in pupitres if p.soliste] if not pupitres: return '' if not prefix: return str_list_w_last([p.html(tags=tags) for p in pupitres]) pupitres_roles = str_list_w_last([ p.html(tags=tags) for p in pupitres if p.partie.type == Partie.ROLE ]) pupitres_instruments = str_list_w_last([ p.html(tags=tags) for p in pupitres if p.partie.type == Partie.INSTRUMENT ]) if pupitres_roles: out = ugettext('de ') + pupitres_roles if pupitres_instruments: out += ugettext(' avec ') + pupitres_instruments return out return ugettext('pour ') + pupitres_instruments def pupitres_html(self, prefix=False, tags=True, solistes=False): return self.get_pupitres_str(prefix=prefix, tags=tags, solistes=solistes) @model_method_cached() def auteurs_html(self, tags=True): return self.auteurs.html(tags) auteurs_html.short_description = _('auteur(s)') auteurs_html.allow_tags = True auteurs_html.admin_order_field = 'auteurs__individu__nom' def parentes_in_order(self, relation): return getattr(self, relation).order_by('creation_date', 'creation_heure', 'creation_lieu', 'creation_date_approx', 'creation_heure_approx', 'creation_lieu_approx') def meres_in_order(self): return self.parentes_in_order('meres') def filles_in_order(self): return self.parentes_in_order('filles') @property def evenements(self): # We use a subquery, otherwise yearly_counts counts the number of # program elements instead of events. return apps.get_model('libretto', 'Evenement').objects.filter( pk__in=apps.get_model('libretto', 'Evenement').objects.filter( programme__oeuvre__in=self.get_descendants(include_self=True))) def oeuvres_associees(self): # TODO: Limiter à ce que l’utilisateur peut voir. return (Oeuvre.objects.exclude(pk__in=self.get_descendants( include_self=True)).filter( elements_de_programme__evenement__programme__oeuvre=self). annotate(n=Count('elements_de_programme__evenement')).order_by( '-n', *self._meta.ordering)).distinct() def _link_with_number(self): return ugettext('œuvre jouée %s fois avec : %s') % (self.n, self.link()) def get_referent_ancestors_html(self, tags=False, links=False): if not self.pk or self.extrait_de is None or \ (self.genre and self.genre.referent): return '' return self.extrait_de.titre_html(tags=tags, links=links, ancestors_links=links, show_type_extrait=False) def has_titre_significatif(self): return bool(self.titre) def get_titre_significatif(self): return (f'{self.prefixe_titre}{self.titre}' f'{self.coordination}' f'{self.prefixe_titre_secondaire}{self.titre_secondaire}') def has_titre_non_significatif(self): return self.tempo or self.genre_id is not None def get_titre_non_significatif(self, tags=True, caps=False): if not self.has_titre_non_significatif(): return '' if self.genre is None: assert self.tempo != '' l = [capfirst(self.tempo) if caps else self.tempo] else: l = [capfirst(self.genre.nom) if caps else self.genre.nom] if not self.has_titre_significatif(): l.append(self.get_pupitres_str(tags=False, solistes=True)) l.append(next(self.caracteristiques_iterator(tags=tags), None)) return str_list(l, infix=' ') def get_description(self, tags=True): l = [] if self.has_titre_significatif(): l.append(self.get_titre_non_significatif(tags=tags)) caracteristiques = list(self.caracteristiques_iterator(tags=tags)) if self.has_titre_non_significatif(): # La première caractéristique est utilisée dans le titre non # significatif. caracteristiques = caracteristiques[1:] l.extend(caracteristiques) return str_list(l, infix=' ') @model_method_cached() def html(self, tags=True, auteurs=True, titre=True, descr=True, ancestors=True, ancestors_links=False, links=True, show_type_extrait=True): l = [] if auteurs: l.append(self.auteurs_html(tags=tags)) if titre: if ancestors: l.append( self.get_referent_ancestors_html(tags=tags, links=ancestors_links)) if self.has_titre_significatif(): titre_complet = cite(self.get_titre_significatif(), tags=tags) else: titre_complet = self.get_titre_non_significatif( tags=tags, caps=(self.type_extrait is None or self.type_extrait in self.TYPES_EXTRAIT_CACHES)) extrait = capfirst(self.get_extrait(show_type=show_type_extrait)) if extrait: if titre_complet: titre_complet = f'{extrait} {titre_complet}' elif self.type_extrait not in self.TYPES_EXTRAIT_CACHES: titre_complet = extrait url = None if not tags else self.get_absolute_url() l.append(href(url, titre_complet, tags & links)) if descr: l.append(self.get_description(tags=tags)) return mark_safe(str_list(l)) html.short_description = _('rendu HTML') html.allow_tags = True def short_html(self, tags=True, links=False): return self.html(tags=tags, auteurs=False, titre=True, descr=False, ancestors=False, links=links) def titre_html(self, tags=True, links=True, ancestors_links=True, show_type_extrait=True): return self.html(tags, auteurs=False, titre=True, descr=False, ancestors=True, ancestors_links=ancestors_links, links=links, show_type_extrait=show_type_extrait) titre_html.short_description = _('titre') def titre_descr(self, tags=False): return self.html(tags=tags, auteurs=False, titre=True, descr=True, ancestors=True) def titre_descr_html(self): return self.titre_descr(tags=True) def description_html(self, tags=True): return self.html(tags, auteurs=False, titre=False, descr=True) def handle_whitespaces(self): match = re.match(r'^,\s*(.+)$', self.coordination) v = self.coordination if match is None else match.group(1) if v: self.coordination = f', {v}' for attr in ('prefixe_titre', 'prefixe_titre_secondaire', 'coordination'): v = getattr(self, attr) if v and v[-1] not in (' ', "'", '’'): setattr(self, attr, f'{v} ') def related_label(self): txt = force_text(self) auteurs = self.auteurs.html(tags=False) if auteurs: txt += f' ({auteurs})' return txt def __str__(self): return strip_tags(self.titre_html(False)) # strip_tags car on autorise # les rédacteurs à mettre des tags dans les CharFields _str = __str__ _str.short_description = _('œuvre') @staticmethod def autocomplete_search_fields(add_icontains=True): lookups = ('auteurs__individu__nom', 'auteurs__individu__prenoms', 'auteurs__individu__pseudonyme', 'auteurs__ensemble__nom', 'prefixe_titre', 'titre', 'prefixe_titre_secondaire', 'titre_secondaire', 'genre__nom', 'numero', 'coupe', 'tempo', 'sujet', 'surnom', 'nom_courant', 'incipit', 'opus', 'ict', 'pupitres__partie__nom') lookups = [f'{lookup}__unaccent' for lookup in lookups] if add_icontains: return [f'{lookup}__icontains' for lookup in lookups] return lookups
def membres_html(self): return str_list([ membre.html() for membre in self.membres.select_related('individu', 'instrument')])