from reversion import revisions as reversion import logging from taggit.managers import TaggableManager from django.db import models from django.utils import timezone from django.utils.functional import cached_property from django.urls import reverse from polymorphic.models import PolymorphicModel from mamweb.models.base import SeminarModelBase from personalni.models.organizator import Organizator @reversion.register(ignore_duplicates=True) # Pozor na následující řádek. *Nekrmit, asi kouše!* class Problem(SeminarModelBase, PolymorphicModel): class Meta: # Není abstraktní, protože se na něj jinak nedají dělat ForeignKeys. # TODO: Udělat to polymorfní (pomocí django-polymorphic), abychom dostali # po těch vazbách přímo tu úlohu/témátko vč. fieldů, které nejsou součástí # modelu Problem? # abstract = True db_table = 'seminar_problemy' verbose_name = 'Problém' verbose_name_plural = 'Problémy' ordering = ['nazev'] # Interní ID id = models.AutoField(primary_key=True) # Název nazev = models.CharField('název', max_length=256) # Zveřejnitelný na stránky # Problém má podproblémy nadproblem = models.ForeignKey( 'self', verbose_name='nadřazený problém', related_name='podproblem', null=True, blank=True, on_delete=models.SET_NULL, ) STAV_NAVRH = 'navrh' STAV_ZADANY = 'zadany' STAV_VYRESENY = 'vyreseny' STAV_SMAZANY = 'smazany' STAV_CHOICES = [ (STAV_NAVRH, 'Návrh'), (STAV_ZADANY, 'Zadaný'), (STAV_VYRESENY, 'Vyřešený'), (STAV_SMAZANY, 'Smazaný'), ] stav = models.CharField( 'stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH, ) # Téma je taky Problém, takže má stavy, "zadané" témátko je aktuálně otevřené a dá se k němu něco poslat (řešení nebo článek) zamereni = TaggableManager( verbose_name='zaměření', help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True, ) poznamka = models.TextField( 'org poznámky (HTML)', blank=True, help_text='Neveřejný návrh úlohy, návrh řešení, text zadání, poznámky ...', ) autor = models.ForeignKey( Organizator, verbose_name='autor problému', related_name='autor_problemu_%(class)s', null=True, blank=True, on_delete=models.SET_NULL, ) garant = models.ForeignKey( Organizator, verbose_name='garant zadaného problému', related_name='garant_problemu_%(class)s', null=True, blank=True, on_delete=models.SET_NULL, ) opravovatele = models.ManyToManyField( Organizator, verbose_name='opravovatelé', blank=True, related_name='opravovatele_%(class)s', ) kod = models.CharField( 'lokální kód', max_length=32, blank=True, default='', help_text='Číslo/kód úlohy v čísle nebo kód tématu/článku/seriálu v ročníku', ) vytvoreno = models.DateTimeField( 'vytvořeno', default=timezone.now, blank=True, editable=False, ) def __str__(self): return self.nazev # Implicitini implementace, jednotlivé dědící třídy si přepíšou @cached_property def kod_v_rocniku(self): if self.stav == Problem.STAV_ZADANY or self.stav == Problem.STAV_VYRESENY: if self.nadproblem: return self.nadproblem.kod_v_rocniku+".{}".format(self.kod) return str(self.kod) logger = logging.getLogger(__name__) logger.warning(f"K problému {self} byl vyžadován kód v ročníku, i když není zadaný ani vyřešený.") return '' # def verejne(self): # # aktuálně podle stavu problému # # FIXME pro některé problémy možná chceme override # # FIXME vrací veřejnost čistě problému, nezávisle na čísle, ve kterém je. # # Je to tak správně? Podle aktuální představy ano. # stav_verejny = False # if self.stav == 'zadany' or self.stav == 'vyreseny': # stav_verejny = True # print("stav_verejny: {}".format(stav_verejny)) # # cislo_verejne = False # cislonode = self.cislo_node() # if cislonode is None: # # problém nemá vlastní node, veřejnost posuzujeme jen podle stavu # print("empty node") # return stav_verejny # else: # cislo_zadani = cislonode.cislo # if (cislo_zadani and cislo_zadani.verejne()): # print("cislo: {}".format(cislo_zadani)) # cislo_verejne = True # print("stav_verejny: {}".format(stav_verejny)) # print("cislo_verejne: {}".format(cislo_verejne)) # return (stav_verejny and cislo_verejne) # verejne.boolean = True def verejne_url(self): return reverse('seminar_problem', kwargs={'pk': self.id}) def admin_url(self): return reverse('admin:seminar_problem_change', args=(self.id, )) @cached_property def hlavni_problem(self): """Pro daný problém vrátí jeho nejvyšší nadproblém.""" problem = self while not (problem.nadproblem is None): problem = problem.nadproblem return problem # FIXME - k úloze def body_v_zavorce(self): """Vrať string s body v závorce jsou-li u problému vyplněné, jinak '' Je-li desetinná část nulová, nezobrazuj ji. """ pocet_bodu = None if self.body: b = self.body pocet_bodu = int(b) if int(b) == b else b return "({}\u2009b)".format(pocet_bodu) if self.body else ""