diff --git a/seminar/models.py b/seminar/models.py index abf3393e..10d05395 100644 --- a/seminar/models.py +++ b/seminar/models.py @@ -68,10 +68,6 @@ class Skola(SeminarModelBase): aesop_id = models.CharField(u'Aesop ID', max_length=32, blank=True, default='', help_text=u'Aesopi ID typu "izo:..." nebo "aesop:..."') - # Staré (do 2015) MAMOPER.MM_RIESITELIA.ID z DAKOSu -- jen u importovaných záznamů - import_dakos_id = models.CharField(u'importované DKSROOT.V_SKOLA.ID', max_length=32, blank=True, default='', - help_text=u'DKSROOT.V_SKOLA.ID z DAKOS importu, jen historický význam') - # IZO školy (jen české školy) izo = models.CharField(u'IZO', max_length=32, blank=True, help_text=u'IZO školy (jen české školy)') @@ -103,42 +99,37 @@ class Skola(SeminarModelBase): poznamka = models.TextField(u'neveřejná poznámka', blank=True, help_text=u'Neveřejná poznámka ke škole (plain text)') + + kontaktni_osoba = models.ForeignKey(Osoba, verbose_name=u'Kontaktní osoba', + blank=True, null=True) def __str__(self): - return force_unicode(u'%s, %s, %s' % (self.nazev, - self.ulice, - self.mesto)) - - + return force_unicode(u'%s, %s, %s' % (self.nazev, self.ulice, self.mesto)) @reversion.register(ignore_duplicates=True) @python_2_unicode_compatible -class Resitel(SeminarModelBase): - +class Osoba(SeminarModelBase): + class Meta: - db_table = 'seminar_resitele' - verbose_name = u'Řešitel' - verbose_name_plural = u'Řešitelé' - ordering = ['osoba__prijmeni', 'osoba__jmeno'] - - # Interní ID + db_table = 'seminar_osoby' + verbose_name = u'Osoba' + verbose_name_plural = u'Osoby' + ordering = ['prijmeni','jmeno'] + id = models.AutoField(primary_key = True) jmeno = models.CharField(u'jméno', max_length=256) prijmeni = models.CharField(u'příjmení', max_length=256) + prezdivka = models.CharField(u'přezdívka', max_length=256) + # User, pokud má na webu účet user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True, verbose_name=u'uživatel') # Pohlaví. Že ho neznáme se snad nestane (a ušetří to práci při programování) pohlavi_muz = models.BooleanField(u'pohlaví (muž)', default=False) - skola = models.ForeignKey(Skola, blank=True, null=True, verbose_name=u'škola') - - # Očekávaný rok maturity a vyřazení z aktivních řešitelů - rok_maturity = models.IntegerField(u'rok maturity', blank=True, null=True) - email = models.EmailField(u'e-mail', max_length=256, blank=True, default='') telefon = models.CharField(u'telefon', max_length=256, blank=True, default='') @@ -154,17 +145,7 @@ class Resitel(SeminarModelBase): help_text=u'Datum souhlasu se zasíláním MFF materiálů') # Alespoň odhad (rok či i měsíc) - datum_prihlaseni = models.DateField(u'datum přihlášení', default=timezone.now) - - ZASILAT_DOMU = 'domu' - ZASILAT_DO_SKOLY = 'do_skoly' - ZASILAT_NIKAM = 'nikam' - ZASILAT_CHOICES = [ - (ZASILAT_DOMU, u'Domů'), - (ZASILAT_DO_SKOLY, u'Do školy'), - (ZASILAT_NIKAM, u'Nikam'), - ] - zasilat = models.CharField(u'kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU) + datum_registrace = models.DateField(u'datum registrace do semináře', default=timezone.now) # Ulice může být i jen číslo ulice = models.CharField(u'ulice', max_length=256, blank=True, default='') @@ -179,11 +160,21 @@ class Resitel(SeminarModelBase): help_text=u'ISO 3166-1 kód země velkými písmeny (CZ, SK, ...)') poznamka = models.TextField(u'neveřejná poznámka', blank=True, - help_text=u'Neveřejná poznámka k řešiteli (plain text)') + help_text=u'Neveřejná poznámka k osobě (plain text)') - # Staré (do 2015) MAMOPER.MM_RIESITELIA.ID z DAKOS -- jen u importovaných záznamů - import_mamoper_id = models.CharField(u'importované MM_RIESITELIA.ID', max_length=32, blank=True, default='', - help_text=u'MAMOPER.MM_RIESITELIA.ID z DAKOS importu, jen historický význam') + foto = ProcessedImageField(verbose_name='Fotografie osoby', + upload_to='image_osoby/velke/%Y/', null = True, blank = True, + help_text = 'Vlož fotografii osoby o libovolné velikosti', + processors=[ + Transpose(Transpose.AUTO), + ResizeToFit(500, 500, upscale=False) + ], + options={'quality': 95}) + foto_male = ImageSpecField(source='foto', + processors=[ + ResizeToFit(200, 200, upscale=False) + ], + options={'quality': 95}) def plne_jmeno(self): return force_unicode(u'%s %s' % (self.jmeno, self.prijmeni)) @@ -192,30 +183,83 @@ class Resitel(SeminarModelBase): return force_unicode(u'%s.' % (self.jmeno[0])) def __str__(self): - return force_unicode(self.plne_jmeno()) + return force_unicode("Osoba({})".format(self.plne_jmeno())) + +class Prijemce(SeminarModelBase): + class Meta: + db_table = 'seminar_prijemce' + verbose_name = u'příjemce' + verbose_name_plural = u'příjemce' + + + # Interní ID + id = models.AutoField(primary_key = True) + + poznamka = models.TextField(u'neveřejná poznámka', blank=True, + help_text=u'Neveřejná poznámka k příemci čísel (plain text)') + + osoba = models.ForeignKey(Osoba, verbose_name=u'komu', blank=False, null=False, + help_text=u'Které osobě či na jakou adresu se mají zasílat čísla') + + # FIXME: možná chceme něco jako vazbu na osobu XOR školu a počet kusů k zaslání + + +@reversion.register(ignore_duplicates=True) +@python_2_unicode_compatible +class Resitel(SeminarModelBase): + + class Meta: + db_table = 'seminar_resitele' + verbose_name = u'Řešitel' + verbose_name_plural = u'Řešitelé' + ordering = ['osoba'] + + # Interní ID + id = models.AutoField(primary_key = True) + + osoba = models.ForeignKey(Osoba, blank=False, null=False, verbose_name=u'osoba') + + skola = models.ForeignKey(Skola, blank=True, null=True, verbose_name=u'škola') + + # Očekávaný rok maturity a vyřazení z aktivních řešitelů + rok_maturity = models.IntegerField(u'rok maturity', blank=True, null=True) + + ZASILAT_DOMU = 'domu' + ZASILAT_DO_SKOLY = 'do_skoly' + ZASILAT_NIKAM = 'nikam' + ZASILAT_CHOICES = [ + (ZASILAT_DOMU, u'Domů'), + (ZASILAT_DO_SKOLY, u'Do školy'), + (ZASILAT_NIKAM, u'Nikam'), + ] + zasilat = models.CharField(u'kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU) + + + poznamka = models.TextField(u'neveřejná poznámka', blank=True, + help_text=u'Neveřejná poznámka k řešiteli (plain text)') + def export_row(self): - "Slovnik pro pouziti v OVVP (OPMK) exportu" + "Slovnik pro pouziti v AESOP exportu" return { - 'id': self.id, - 'name': self.jmeno, - 'surname': self.prijmeni, - 'gender': 'M' if self.pohlavi_muz else 'F', - 'born': self.datum_narozeni.isoformat() if self.datum_narozeni else '', - 'email': self.email, - 'end-year': self.rok_maturity or '', - - # TODO(gavento): Adresa skoly, kdyz preferuje zasilani tam? - 'street': self.ulice, - 'town': self.mesto, - 'postcode': self.psc, - 'country': self.stat, - - 'spam-flag': 'Y' if self.datum_souhlasu_zasilani else '', - 'spam-date': self.datum_souhlasu_zasilani.isoformat() if self.datum_souhlasu_zasilani else '', - - 'school': self.skola.aesop_id if self.skola else '', - 'school-name': str(self.skola) if self.skola else 'Skola neni znama', + 'id': self.id, + 'name': self.osoba.jmeno, + 'surname': self.osoba.prijmeni, + 'gender': 'M' if self.osoba.pohlavi_muz else 'F', + 'born': self.osoba.datum_narozeni.isoformat() if self.osoba.datum_narozeni else '', + 'email': self.osoba.email, + 'end-year': self.rok_maturity or '', + + 'street': self.osoba.ulice, + 'town': self.osoba.mesto, + 'postcode': self.osoba.psc, + 'country': self.osoba.stat, + + 'spam-flag': 'Y' if self.osoba.datum_souhlasu_zasilani else '', + 'spam-date': self.osoba.datum_souhlasu_zasilani.isoformat() if self.osoba.datum_souhlasu_zasilani else '', + + 'school': self.skola.aesop_id if self.skola else '', + 'school-name': str(self.skola) if self.skola else 'Skola neni znama', } def rocnik(self, rocnik): @@ -271,6 +315,7 @@ class Rocnik(SeminarModelBase): def __str__(self): return force_unicode(u'%s (%d/%d)' % (self.rocnik, self.prvni_rok, self.prvni_rok+1)) + # Ročník v římských číslech def roman(self): return force_unicode(roman(int(self.rocnik))) @@ -347,7 +392,7 @@ class Cislo(SeminarModelBase): help_text=u'Datum pro příjem řešení pro účast na soustředění') verejne_db = models.BooleanField(u'číslo zveřejněno', - db_column='verejne', default=False) + db_column='verejne', default=False) verejna_vysledkovka = models.BooleanField( u'zveřejněna výsledkovka', @@ -361,29 +406,6 @@ class Cislo(SeminarModelBase): pdf = models.FileField(u'pdf', upload_to=cislo_pdf_filename, null=True, blank=True, help_text=u'Pdf čísla, které si mohou řešitelé stáhnout') - FAZE_ADMIN = u'admin' - FAZE_TEX = u'tex' - FAZE_NAHRANO = u'nahrano' - FAZE_CHOICES = [ - (FAZE_ADMIN, u'Úpravy na webu'), - (FAZE_TEX, u'Úpravy v TeXu'), - (FAZE_NAHRANO, u'Nahráno na web'), - ] - faze = models.CharField( - u'Fáze vytváření obsahu', - max_length=32, - default=FAZE_ADMIN, - choices=FAZE_CHOICES, - help_text=( - u'Během fáze "{}" se obsah čísla vytváří (a případně ' - u'komentuje) ve webovém rozhraní. Během fáze "{}" už obsah ve ' - u'webovém rozhraní editovat nelze a návrhy na úpravy se píší ' - u'do korekturovátka a zanášejí do gitu. Z něj se pak vygeneruje ' - u'verze pro web a číslo se přepne do fáze "{}", což jen znamená, ' - u'že už nejde automaticky stáhnout obsah pro založení čísla v ' - u'TeXu.' - ).format(FAZE_CHOICES[0][1], FAZE_CHOICES[1][1], FAZE_CHOICES[2][1]) - ) def kod(self): return u'%s.%s' % (self.rocnik.rocnik, self.cislo) @@ -432,7 +454,7 @@ class Cislo(SeminarModelBase): class Problem(SeminarModelBase): class Meta: - db_table = 'seminar_problemy' + abstract = True verbose_name = u'Problém' verbose_name_plural = u'Problémy' ordering = ['nazev'] @@ -443,81 +465,55 @@ class Problem(SeminarModelBase): # Název nazev = models.CharField(u'název', max_length=256) - TYP_ULOHA = 'uloha' - TYP_TEMA = 'tema' - TYP_SERIAL = 'serial' - TYP_KONFERA = 'konfera' - TYP_ORG_CLANEK = 'org-clanek' - TYP_RES_CLANEK = 'res-clanek' - TYP_CHOICES = [ - (TYP_ULOHA, u'Úloha'), - (TYP_TEMA, u'Téma'), - (TYP_SERIAL, u'Seriál'), - (TYP_KONFERA, u'Konfera'), - (TYP_ORG_CLANEK, u'Organizátorský článek'), - (TYP_RES_CLANEK, u'Řešitelský článek'), - ] - typ = models.CharField(u'typ problému', max_length=32, choices=TYP_CHOICES, blank=False, default=TYP_ULOHA) + # Problém má podproblémy + nadproblem = models.ForeignKey(Problem, verbose_name=u'nadřazený problém', + related_name='nadproblem', null=True, blank=True) STAV_NAVRH = 'navrh' STAV_ZADANY = 'zadany' + STAV_VYRESENY = 'vyreseny' STAV_SMAZANY = 'smazany' STAV_CHOICES = [ (STAV_NAVRH, u'Návrh'), (STAV_ZADANY, u'Zadaný'), + (STAV_VYRESENY, u'Vyřešený'), (STAV_SMAZANY, u'Smazaný'), ] stav = models.CharField(u'stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH) zamereni = TaggableManager(verbose_name=u'zaměření', help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True) - text_org = models.TextField(u'org poznámky (HTML)', blank=True, + poznamka = models.TextField(u'org poznámky (HTML)', blank=True, help_text=u'Neveřejný návrh úlohy, návrh řešení, text zadání, poznámky ...') - text_zadani = models.TextField(u'veřejné zadání (HTML)', blank=True, - help_text=u'Veřejný text zadání (HTML)') - text_reseni = models.TextField(u'veřejné řešení (HTML)', blank=True, - help_text=u'Veřejný text řešení (HTML, u témat i příspěvky a komentáře)') + autor = models.ForeignKey(Organizator, verbose_name=u'autor problému', + related_name='autor_problemu', null=True, blank=True) - autor = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=u'autor problému', related_name='autor_uloh', null=True, blank=True) + garant = models.ForeignKey(Organizator, verbose_name=u'garant zadaného problému', + related_name='garant_problemu', null=True, blank=True) - opravovatel = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=u'opravovatel', null=True, blank=True, - related_name='opravovatel_uloh') + opravovatele = models.ManyToManyField(Organizator, verbose_name=u'opravovatelé', + null=True, blank=True, related_name='opravovatele_uloh') kod = models.CharField(u'lokální kód', max_length=32, blank=True, default='', help_text=u'Číslo/kód úlohy v čísle nebo kód tématu/článku/seriálu v ročníku') - cislo_zadani = models.ForeignKey(Cislo, verbose_name=u'číslo zadání', blank=True, null=True, related_name=u'zadane_problemy') - - cislo_reseni = models.ForeignKey(Cislo, verbose_name=u'číslo řešení', blank=True, null=True, related_name=u'resene_problemy', - help_text=u'Číslo s řešením úlohy, jen pro úlohy') - - body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name=u'maximum bodů', blank=True, null=True) - timestamp = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False) + vytvoreno = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False) - # Staré (do 2014) ID problému z DAKOSU -- jen u importovaných záznamů - import_dakos_id = models.CharField(u'importované ID s typem', max_length=32, blank=True, default='', - help_text=(u'ID z importu z DAKOSU s prefixem podle původu: "AZAD:xxx (MAMOPER.MM_AZAD), "' + - u'"DOZ:xxx" (MAMOPER.MM_DOZ), "ZAD:rocnik.cislo.uloha.typ" (MAMOPER.MM_ZADANIA), "ULOHA:xxx" (MAMOPER.MM_ULOHY)')) def __str__(self): return force_unicode(u'%s' % (self.nazev, )) + # Implicitini implementace, jednotlivé dědící třídy si přepíšou def kod_v_rocniku(self): if self.stav == 'zadany': - if self.typ == self.TYP_ULOHA: - return force_unicode(u"%s.u%s" % (self.cislo_zadani.cislo, self.kod,)) - if self.typ == self.TYP_TEMA: - return force_unicode(u"t%s" % (self.kod,)) - else: - return force_unicode(self.kod) + if self.nadproblem: + return force_unicode(self.nadproblem.kod_v_rocniku()+".{}".format(self.kod)) + return force_unicode(str(self.kod)) return u'' - def nazev_typu(self): - return dict(self.TYP_CHOICES)[self.typ] - def verejne(self): return (self.cislo_zadani and self.cislo_zadani.verejne()) verejne.boolean = True @@ -531,6 +527,7 @@ class Problem(SeminarModelBase): else: return reverse('admin:seminar_problemnavrh_change', args=(self.id, )) +# FIXME - k úloze def body_v_zavorce(self): """Vrať string s body v závorce jsou-li u problému vyplněné, jinak '' @@ -542,6 +539,74 @@ class Problem(SeminarModelBase): pocet_bodu = int(b) if int(b) == b else b return u"({}\u2009b)".format(pocet_bodu) if self.body else "" +class Tema(Problem): + class Meta: + db_table = 'seminar_temata' + verbose_name = u'Téma' + verbose_name_plural = u'Témata' + + TEMA_TEMA = 'tema' + TEMA_SERIAL = 'serial' + TEMA_CHOICES = [ + (TEMA_TEMA, u'Téma'), + (TEMA_SERIAL, u'Seriál'), + ] + typ = models.CharField(u'Typ tématu', max_length=16, choices=TEMA_CHOICES, blank=False, default=TEMA_TEMA) + + rocnik = models.ForeignKey(Rocnik, verbose_name=u'ročník', related_name='rocnik',blank=True, null=True) + + def kod_v_rocniku(self): + if self.stav == 'zadany': + if self.nadproblem: + return force_unicode(self.nadproblem.kod_v_rocniku()+".t{}".format(self.kod)) + return force_unicode("t{}".format(self.kod)) + return u'' + +class Clanek(Problem): + class Meta: + db_table = 'seminar_clanky' + verbose_name = u'Článek' + verbose_name_plural = u'Články' + + cislo = models.ForeignKey(Cislo, verbose_name=u'číslo', related_name='cislo', blank=True, null=True) + def kod_v_rocniku(self): + if self.stav == 'zadany': +# Nemělo by být potřeba +# if self.nadproblem: +# return force_unicode(self.nadproblem.kod_v_rocniku()+".c{}".format(self.kod)) + return force_unicode("c{}".format(self.kod)) + return u'' + +class Uloha(Problem): + class Meta: + db_table = 'seminar_ulohy' + verbose_name = u'Úloha' + verbose_name_plural = u'Úlohy' + + + zadani = models.ForeignKey(Text, verbose_name=u'veřejné zadání', related_name='zadani', blank=True, null=True) + + vzorak = models.ForeignKey(Text, verbose_name=u'vzorové řešení', related_name='vzorak', blank=True, null=True) + + + cislo_zadani = models.ForeignKey(Cislo, verbose_name=u'číslo zadání', blank=True, null=True, related_name=u'zadane_ulohy') + + cislo_deadline = models.ForeignKey(Cislo, verbose_name=u'číslo deadlinu', blank=True, null=True, related_name=u'deadlinove_ulohy') + + cislo_reseni = models.ForeignKey(Cislo, verbose_name=u'číslo řešení', blank=True, null=True, related_name=u'resene_ulohy', + help_text=u'Číslo s řešením úlohy, jen pro úlohy') + + max_body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name=u'maximum bodů', blank=True, null=True) + + def kod_v_rocniku(self): + if self.stav == 'zadany': + name=u"{}.u{}".format(self.cislo_zadani.cislo,self.kod) + if self.nadproblem: + return force_unicode(self.nadproblem.kod_v_rocniku()+name) + return force_unicode(name) + return u'' + + @reversion.register(ignore_duplicates=True) @python_2_unicode_compatible @@ -551,20 +616,20 @@ class Reseni(SeminarModelBase): db_table = 'seminar_reseni' verbose_name = u'Řešení' verbose_name_plural = u'Řešení' - ordering = ['problem_id', 'resitel__prijmeni', 'resitel__jmeno',] + ordering = ['-problem_id', 'resitel'] # Interní ID id = models.AutoField(primary_key = True) - problem = models.ForeignKey(Problem, verbose_name=u'problém', related_name='reseni') - - resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel', related_name='reseni') + # Ke každé dvojici řešní a problém existuje nanejvýš jedno hodnocení, doplnění vazby. + problem = models.ManyToManyField(Problem, verbose_name=u'problém', help_text=u'Problém', + through='Hodnoceni') - body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name=u'body', blank=True, null=True) + resitele = models.ManyToManyField(Resitel, verbose_name=u'autoři řešení', + help_text=u'Seznam autorů řešení', through='Reseni_Resitele') - cislo_body = models.ForeignKey(Cislo, verbose_name=u'číslo pro body', related_name='bodovana_reseni', blank=True, null=True) - timestamp = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False) + cas_doruceni = models.DateTimeField(u'čas_doručení', default=timezone.now, blank=True) FORMA_PAPIR = 'papir' FORMA_EMAIL = 'email' @@ -574,51 +639,87 @@ class Reseni(SeminarModelBase): (FORMA_EMAIL, u'Emailem'), (FORMA_UPLOAD, u'Upload přes web'), ] - forma = models.CharField(u'forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False, default=FORMA_EMAIL) + forma = models.CharField(u'forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False, + default=FORMA_EMAIL) + text_cely = models.ForeignKey(Text, verbose_name=u'Plná verze textu řešení', + blank=True, null=True) + + text_zkraceny = models.ManyToManyField(Text, verbose_name=u'zkrácené verze řešení', + help_text=u'Seznam úryvků z řešení') + poznamka = models.TextField(u'neveřejná poznámka', blank=True, help_text=u'Neveřejná poznámka k řešení (plain text)') + zverejneno = models.BooleanField(u'řešení zveřejněno', default=False, + help_text=u'Udává, zda je řešení zveřejněno') + def __str__(self): - return force_unicode(u"%s: %s (%sb)" % (self.resitel.plne_jmeno(), self.problem.nazev, self.body)) + return force_unicode(u"%s: %s".format(self.resitel.osoba.plne_jmeno(), + self.problem.nazev)) # NOTE: Potenciální DB HOG (bez select_related) - def save(self, *args, **kwargs): - if ((self.cislo_body is None) and (self.problem.cislo_reseni) and - (self.problem.typ == Problem.TYP_ULOHA)): - self.cislo_body = self.problem.cislo_reseni - super(Reseni, self).save(*args, **kwargs) +## Pravdepodobne uz nebude potreba: +# def save(self, *args, **kwargs): +# if ((self.cislo_body is None) and (self.problem.cislo_reseni) and +# (self.problem.typ == Problem.TYP_ULOHA)): +# self.cislo_body = self.problem.cislo_reseni +# super(Reseni, self).save(*args, **kwargs) + +class Hodnoceni(SeminarModelBase): + class Meta: + db_table = 'seminar_hodnoceni' + verbose_name = u'Hodnocení' + verbose_name_plular = u'Hodnocení' + + # Interní ID + id = models.AutoField(primary_key = True) + + + body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name=u'body', + blank=False, null=False) + + cislo_body = models.ForeignKey(Cislo, verbose_name=u'číslo pro body', + related_name='hodnoceni', blank=False, null=False) + + reseni = models.ForeignKey(Reseni, verbose_name=u'řešení') + + problem = models.ForeignKey(Problem, verbose_name=u'problém') -def aux_generate_filename(self, filename): - """Pomocná funkce generující ošetřený název souboru v adresáři s datem""" - clean = get_valid_filename( - unidecode(filename.replace('/', '-').replace('\0', '')) - ) - datedir = timezone.now().strftime('%Y-%m') - fname = "%s_%s" % ( - timezone.now().strftime('%Y-%m-%d-%H:%M'), - clean) - return os.path.join(datedir, fname) + +## FIXME: Budeme řešit později, pokud to bude potřeba. +#def aux_generate_filename(self, filename): +# """Pomocná funkce generující ošetřený název souboru v adresáři s datem""" +# clean = get_valid_filename( +# unidecode(filename.replace('/', '-').replace('\0', '')) +# ) +# datedir = timezone.now().strftime('%Y-%m') +# fname = "%s_%s" % ( +# timezone.now().strftime('%Y-%m-%d-%H:%M'), +# clean) +# return os.path.join(datedir, fname) # Django neumí jednoduše serializovat partial nebo třídu s __call__ # (https://docs.djangoproject.com/en/1.8/topics/migrations/), # neprojdou pak migrace. Takže rozlišení funkcí generujících názvy souboru # podle adresáře řešíme takto. +## +## FIXME: Budeme řešit později, pokud to bude potřeba. +#def generate_filename_konfera(self, filename): +# return os.path.join( +# settings.SEMINAR_KONFERY_DIR, +# aux_generate_filename(self, filename) +# ) -def generate_filename_konfera(self, filename): - return os.path.join( - settings.SEMINAR_KONFERY_DIR, - aux_generate_filename(self, filename) - ) - - -def generate_filename(self, filename): - return os.path.join( - settings.SEMINAR_RESENI_DIR, - aux_generate_filename(self, filename) - ) +## +## FIXME: Budeme řešit později, pokud to bude potřeba. +#def generate_filename(self, filename): +# return os.path.join( +# settings.SEMINAR_RESENI_DIR, +# aux_generate_filename(self, filename) +# ) @reversion.register(ignore_duplicates=True) @@ -636,7 +737,7 @@ class PrilohaReseni(SeminarModelBase): reseni = models.ForeignKey(Reseni, verbose_name=u'řešení', related_name='prilohy') - timestamp = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False) + vytvoreno = models.DateTimeField(u'vytvořeno', default=timezone.now, blank=True, editable=False) soubor = models.FileField(u'soubor', upload_to = generate_filename) @@ -662,7 +763,7 @@ class Pohadka(SeminarModelBase): text = models.TextField(u'Text pohádky') uloha = models.ForeignKey( - Problem, + Uloha, verbose_name=u'Úloha', related_name='pohadky' ) @@ -672,7 +773,7 @@ class Pohadka(SeminarModelBase): pred = models.BooleanField(u'Před úlohou', default=True) autor = models.ForeignKey( - settings.AUTH_USER_MODEL, + Organizator, verbose_name="Autor pohádky", # Při nahrávání z TeXu není vyplnění vyžadováno, v adminu je @@ -680,7 +781,7 @@ class Pohadka(SeminarModelBase): blank=False ) - timestamp = models.DateTimeField( + vytvoreno = models.DateTimeField( u'Vytvořeno', default=timezone.now, blank=True, @@ -688,73 +789,49 @@ class Pohadka(SeminarModelBase): ) def __str__(self): - uryvek = self.text if len(self.text) < (50-3) else self.text[:50]+"..." + uryvek = self.text if len(self.text) < 50 else self.text[:(50-3)]+"..." return force_unicode(uryvek) @reversion.register(ignore_duplicates=True) -class Prispevek(SeminarModelBase): - problem = models.ForeignKey(Problem, verbose_name='Problém') # TODO autokompleet - nazev = models.CharField('Název', max_length=200) - reseni = models.OneToOneField(Reseni, verbose_name='Řešení', - blank = True, null = True) - text_org = models.TextField('Orgovský text', blank = True, null = True) - text_resitel = models.TextField('Řešitelský text', blank = True, null = True) - zverejnit = models.BooleanField('Zveřejnit?') +@python_2_unicode_compatible +class Organizator(SeminarModelBase): +# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu - class Meta: - verbose_name = 'Příspěvek k problému' - verbose_name_plural = 'Příspěvky k problémům' + osoba = models.ForeignKey(Osoba, verbose_name=u'osoba', related_name='org' + help_text=u'osobní údaje organizátora', null=False, blank=False) - def __unicode__(self): - if self.reseni: - return force_unicode(self.nazev) + ' (' + \ - force_unicode(self.reseni.resitel) + ') ' - else: - return force_unicode(self.nazev) + ' ' + vytvoreno = models.DateTimeField( + u'Vytvořeno', + default=timezone.now, + blank=True, + editable=False + ) + organizuje_od = models.DateTimeField('Organizuje od', blank=False, null=False) + + organizuje_do = models.DateTimeField('Organizuje do', blank=True, null=True) -@reversion.register(ignore_duplicates=True) -@python_2_unicode_compatible -class Organizator(models.Model): - user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name='Osoba', - help_text = 'Vyber účet spřažený s organizátorem.') - prezdivka = models.CharField('Přezdívka', max_length = 32, - null = True, blank = True) - organizuje_od_roku = models.IntegerField('Organizuje od roku', - null = True, blank = True) - organizuje_do_roku = models.IntegerField('Organizuje do roku', - null = True, blank = True) studuje = models.CharField('Studium aj.', max_length = 256, null = True, blank = True, - help_text="Např. 'Studuje Obecnou fyziku (Bc.), 3. ročník', " + help_text=u"Např. 'Studuje Obecnou fyziku (Bc.), 3. ročník', " "'Vystudovala Diskrétní modely a algoritmy (Mgr.)' nebo " "'Přednáší na MFF'") - strucny_popis_organizatora = models.TextField('Stručný popis organizátora', + + strucny_popis_organizatora = models.TextField(u'Stručný popis organizátora', null = True, blank = True) - foto = ProcessedImageField(verbose_name='Fotografie organizátora', - upload_to='image_organizatori/velke/%Y/', null = True, blank = True, - help_text = 'Vlož fotografii organizátora o libovolné velikosti', - processors=[ - Transpose(Transpose.AUTO), - ResizeToFit(500, 500, upscale=False) - ], - options={'quality': 95}) - foto_male = ImageSpecField(source='foto', - processors=[ - ResizeToFit(200, 200, upscale=False) - ], - options={'quality': 95}) + + skola = models.CharField(u'Škola, kterou studuje', max_length = 256, null=True, blank=True, + help_text=u"Škola, např. MFF, VŠCHT, VUT, ... prostě aby se nemuselo psát do studuje" + "školu, ale jen obor, možnost zobrazit zvlášť") def __str__(self): - if self.prezdivka: - return u"%s '%s' %s" % (self.user.first_name, - self.prezdivka, - self.user.last_name) + if self.osoba.prezdivka: + return u"%s '%s' %s".format(self.osoba.jmeno, + self.osoba.prezdivka, + self.osoba.prijmeni) else: - return u"%s %s" % (self.user.first_name, self.user.last_name) + return u"%s %s".format(self.osoba.jmeno, self.osoba.prijmeni) class Meta: verbose_name = 'Organizátor' @@ -811,7 +888,7 @@ class Soustredeni(SeminarModelBase): help_text=u'Exportuje se jen podle tohoto flagu (ne veřejnosti)') def __str__(self): - return force_unicode(u'%s (%s)' % (self.misto, self.datum_zacatku)) + return force_unicode(u'%s (%s)'.format(self.misto, self.datum_zacatku)) def verejne(self): return self.verejne_db @@ -824,7 +901,8 @@ class Soustredeni(SeminarModelBase): @reversion.register(ignore_duplicates=True) @python_2_unicode_compatible -class Soustredeni_Ucastnici(models.Model): +class Soustredeni_Ucastnici(SeminarModelBase): +# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu class Meta: db_table = 'seminar_soustredeni_ucastnici' @@ -843,12 +921,13 @@ class Soustredeni_Ucastnici(models.Model): help_text=u'Neveřejná poznámka k účasti (plain text)') def __str__(self): - return force_unicode(u'%s na %s' % (self.resitel, self.soustredeni, )) + return force_unicode(u'%s na %s'.format(self.resitel, self.soustredeni)) # NOTE: Poteciální DB HOG bez select_related @reversion.register(ignore_duplicates=True) @python_2_unicode_compatible -class Soustredeni_Organizatori(models.Model): +class Soustredeni_Organizatori(SeminarModelBase): +# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu class Meta: db_table = 'seminar_soustredeni_organizatori' @@ -867,7 +946,7 @@ class Soustredeni_Organizatori(models.Model): help_text=u'Neveřejná poznámka k účasti organizátora (plain text)') def __str__(self): - return force_unicode(u'%s na %s' % (self.organizator, self.soustredeni, )) + return force_unicode(u'%s na %s'.format(self.organizator, self.soustredeni)) # NOTE: Poteciální DB HOG bez select_related @@ -881,35 +960,49 @@ class Konfera(models.Model): verbose_name_plural = u'Konfery' # Interní ID id = models.AutoField(primary_key = True) + nazev = models.CharField(u'název konfery', max_length=40, help_text = u'Název konfery') - popis = models.TextField(u'popis konfery', blank=True, - help_text=u'Popis konfery k zobrazení na webu') + + anotace = models.TextField(u'anotace', blank=True, + help_text=u'Popis, o čem bude konfera.') + abstrakt = models.TextField(u'abstrakt', blank=True, help_text=u'Abstrakt konfery tak, jak byl uveden ve sborníku') + organizator = models.ForeignKey(Organizator, verbose_name=u'organizátor', related_name='konfery', on_delete = models.SET_NULL, null=True) + ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci konfery', help_text=u'Seznam účastníků konfery', through='Konfery_Ucastnici') - soustredeni = models.ForeignKey(Soustredeni, verbose_name=u'soustředění', related_name='konfery', - on_delete = models.SET_NULL, null=True) - org_poznamka = models.TextField(u'neveřejná poznámka', blank=True, + + soustredeni = models.ForeignKey(Soustredeni, verbose_name=u'soustředění', + related_name='konfery', on_delete = models.SET_NULL, null=True) + + poznamka = models.TextField(u'neveřejná poznámka', blank=True, help_text=u'Neveřejná poznámka ke konfeře(plain text)') - prispevek = models.ForeignKey(Problem, verbose_name=u'příspěvek do čísla', related_name='konfery', - help_text=u'Účastnický přípěvek o konfeře',on_delete = models.SET_NULL, null=True, blank=True) + + reseni = models.ForeignKey(Reseni, verbose_name=u'článek ke konfeře', related_name='konfery', + help_text=u'Účastnický přípěvek o konfeře', on_delete = models.SET_NULL, + null=True, blank=True) + TYP_VELETRH = 'veletrh' TYP_PREZENTACE = 'prezentace' TYP_CHOICES = [ (TYP_VELETRH, u'Veletrh (postery)'), (TYP_PREZENTACE, u'Prezentace (přednáška)'), ] - typ_prezentace = models.CharField(u'typ prezentace', max_length=16, choices=TYP_CHOICES, blank=False, default=TYP_VELETRH) + typ_prezentace = models.CharField(u'typ prezentace', max_length=16, choices=TYP_CHOICES, + blank=False, default=TYP_VELETRH) + prezentace = models.FileField(u'prezentace',help_text = u'Prezentace nebo fotka posteru', upload_to = generate_filename_konfera, blank=True) - materialy = models.FileField(u'materialy',help_text = u'Další materiály ke konfeře zabalené do jednoho souboru', + + materialy = models.FileField(u'materialy', + help_text = u'Další materiály ke konfeře zabalené do jednoho souboru', upload_to = generate_filename_konfera, blank=True) def __str__(self): - return force_unicode(u"%s: (%s)" % (self.nazev, self.soustredeni)) + return force_unicode(u"%s: (%s)".format(self.nazev, self.soustredeni)) @@ -934,79 +1027,124 @@ class Konfery_Ucastnici(models.Model): help_text=u'Neveřejná poznámka k účasti (plain text)') def __str__(self): - return force_unicode(u'%s na %s' % (self.resitel, self.konfera, )) + return force_unicode(u'%s na %s'.format(self.resitel, self.konfera, )) # NOTE: Poteciální DB HOG bez select_related - -@python_2_unicode_compatible -class VysledkyBase(SeminarModelBase): - +class Obrazek(SeminarModelBase): class Meta: - verbose_name = u'Řádek výsledkovky' - verbose_name_plural = u'Řádky výsledkovky' - ordering = ['body'] - abstract = True - managed = False - - dummy_id = models.CharField(u'dummy ID pro view', max_length=32, primary_key=True, db_column='id') - - cislo = models.ForeignKey(Cislo, verbose_name=u'číslo pro body', db_column='cislo_id', on_delete=models.DO_NOTHING) - - resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel', db_column='resitel_id', on_delete=models.DO_NOTHING) - - body = models.DecimalField(max_digits=8, decimal_places=1, db_column='body', - verbose_name=u'body za číslo') - - def __str__(self): - return force_unicode(u"%s: %sb (%s)" % (self.resitel.plne_jmeno(), self.body, str(self.cislo))) - # NOTE: DB zatez pri vypisu (ale nepouzivany) + db_table = 'seminar_obrazky' + verbose_name = u'obrázek' + verbose_name_plural = u'obrázky' + # Interní ID + id = models.AutoField(primary_key = True) -class VysledkyZaCislo(VysledkyBase): + na_web = models.ImageField(u'obrázek na web', upload_to='obrazky/%Y/%m/%d/', + null=True, blank=True) - class Meta: - db_table = 'seminar_body_za_cislo' - abstract = False - managed = False + text = models.ForeignKey(Text, verbose_name='text', help_text=u'text, ve kterém + se obrázek vyskytuje', null=False, blank=False) + do_cisla_barevny = models.FileField(u'barevný obrázek do čísla', + help_text = u'Barevná verze obrázku do čísla', + upload_to = 'obrazky/%Y/%m/%d/', blank=True, null=True) -class VysledkyKCisluZaRocnik(VysledkyBase): + do_cisla_cernobily = models.FileField(u'černobílý obrázek do čísla', + help_text = u'Černobílá verze obrázku do čísla', + upload_to = 'obrazky/%Y/%m/%d/', blank=True, null=True) +class Text(SeminarModelBase): class Meta: - db_table = 'seminar_body_k_cislu_rocnik' - abstract = False - managed = False - -# body = models.DecimalField(max_digits=8, decimal_places=1, db_column='body', -# verbose_name=u'body do čísla (za ročník)') - + db_table = 'seminar_texty' + verbose_name = u'text' + verbose_name_plular = u'texty' -class VysledkyKCisluOdjakziva(VysledkyBase): + na_web = models.TextField(u'text na web', blank=True, + help_text=u'Text ke zveřejnění na webu') - class Meta: - db_table = 'seminar_body_k_cislu_odjakziva' - abstract = False - managed = False + do_cisla = models.TextField(u'text do čísla', blank=True, + help_text=u'Text ke zveřejnění v čísle') + + # obrázky mají návaznost opačným směrem (vazba z druhé strany) +## FIXME: Logiku přesunout do views. +#@python_2_unicode_compatible +#class VysledkyBase(SeminarModelBase): +# +# class Meta: +# verbose_name = u'Řádek výsledkovky' +# verbose_name_plural = u'Řádky výsledkovky' +# ordering = ['body'] +# abstract = True +# managed = False +# +# dummy_id = models.CharField(u'dummy ID pro view', max_length=32, primary_key=True, +# db_column='id') +# +# cislo = models.ForeignKey(Cislo, verbose_name=u'číslo pro body', db_column='cislo_id', +# on_delete=models.DO_NOTHING) +# +# resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel', db_column='resitel_id', +# on_delete=models.DO_NOTHING) +# # body = models.DecimalField(max_digits=8, decimal_places=1, db_column='body', -# verbose_name=u'body do čísla (i minulé ročníky)') - - -@python_2_unicode_compatible -class VysledkyCelkemKCislu(VysledkyBase): - - class Meta: - db_table = 'seminar_body_celkem_k_cislu' - abstract = False - managed = False +# verbose_name=u'body za číslo') +# +# def __str__(self): +# return force_unicode(u"%s: %sb (%s)".format(self.resitel.plne_jmeno(), self.body, +# str(self.cislo))) +# # NOTE: DB zatez pri vypisu (ale nepouzivany) - body_celkem = models.DecimalField(max_digits=8, decimal_places=1, db_column='body_celkem', - verbose_name=u'body celkem do čísla včetně minulých ročníků') - def __str__(self): - # NOTE: DB HOG (ale nepouzivany) - return force_unicode(u"%s: %sb / %sb (do %s)" % (self.resitel.plne_jmeno(), self.body, self.body_celkem, str(self.cislo))) -#mozna potreba upravit +## FIXME: Logiku přesunout do views. +#class VysledkyZaCislo(VysledkyBase): +# +# class Meta: +# db_table = 'seminar_body_za_cislo' +# abstract = False +# managed = False +# +# +## FIXME: Logiku přesunout do views. +#class VysledkyKCisluZaRocnik(VysledkyBase): +# +# class Meta: +# db_table = 'seminar_body_k_cislu_rocnik' +# abstract = False +# managed = False +# +## body = models.DecimalField(max_digits=8, decimal_places=1, db_column='body', +## verbose_name=u'body do čísla (za ročník)') +# +# +## FIXME: Logiku přesunout do views. +#class VysledkyKCisluOdjakziva(VysledkyBase): +# +# class Meta: +# db_table = 'seminar_body_k_cislu_odjakziva' +# abstract = False +# managed = False +# +## body = models.DecimalField(max_digits=8, decimal_places=1, db_column='body', +## verbose_name=u'body do čísla (i minulé ročníky)') +# +# +## FIXME: Logiku přesunout do views. +#@python_2_unicode_compatible +#class VysledkyCelkemKCislu(VysledkyBase): +# +# class Meta: +# db_table = 'seminar_body_celkem_k_cislu' +# abstract = False +# managed = False +# +# body_celkem = models.DecimalField(max_digits=8, decimal_places=1, db_column='body_celkem', +# verbose_name=u'body celkem do čísla včetně minulých ročníků') +# +# def __str__(self): +# # NOTE: DB HOG (ale nepouzivany) +# return force_unicode(u"%s: %sb / %sb (do %s)" % (self.resitel.plne_jmeno(), self.body, self.body_celkem, str(self.cislo))) +##mozna potreba upravit @reversion.register(ignore_duplicates=True) @@ -1019,7 +1157,8 @@ class Nastaveni(SingletonModel): aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name=u'aktuální ročník', null=False) - aktualni_cislo = models.ForeignKey(Cislo, verbose_name=u'poslední vydané číslo', null=False) + aktualni_cislo = models.ForeignKey(Cislo, verbose_name=u'poslední vydané číslo', + null=False) def __str__(self): return u'Nastavení semináře' @@ -1035,17 +1174,20 @@ class Nastaveni(SingletonModel): @python_2_unicode_compatible class Novinky(models.Model): datum = models.DateField(auto_now_add=True) + text = models.TextField('Text novinky', blank=True, null=True) + obrazek = models.ImageField('Obrázek', upload_to='image_novinky/%Y/%m/%d/', null=True, blank=True) + obrazek_maly = ImageSpecField(source='obrazek', processors=[ ResizeToFit(350, 200, upscale=False) ], options={'quality': 95}) - autor = models.ForeignKey(settings.AUTH_USER_MODEL, - verbose_name='Autor novinky') + autor = models.ForeignKey(Organizator, verbose_name='Autor novinky') + zverejneno = models.BooleanField('Zveřejněno', default="False") def __str__(self): @@ -1054,5 +1196,5 @@ class Novinky(models.Model): class Meta: verbose_name = 'Novinka' verbose_name_plural = 'Novinky' - + ordering = ['-datum']