161 lines
5.1 KiB
Python
161 lines
5.1 KiB
Python
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 '<Není zadaný>'
|
|
|
|
# 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 ""
|