You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1530 lines
46 KiB

# -*- coding: utf-8 -*-
import os
import random
from django.db import models
from django.contrib import auth
from django.utils import timezone
from django.conf import settings
from django.utils.encoding import force_text
from django.utils.text import slugify
from django.urls import reverse
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.utils.text import get_valid_filename
from imagekit.models import ImageSpecField, ProcessedImageField
from imagekit.processors import ResizeToFit, Transpose
from django_countries.fields import CountryField
from solo.models import SingletonModel
from taggit.managers import TaggableManager
from reversion import revisions as reversion
from seminar.utils import roman
from unidecode import unidecode
from polymorphic.models import PolymorphicModel
class SeminarModelBase(models.Model):
5 years ago
class Meta:
abstract = True
5 years ago
def verejne(self):
return False
5 years ago
def get_absolute_url(self):
return self.verejne_url() # TODO "absolute"
5 years ago
def admin_url(self):
model_name = self.__class__.__name__.lower()
return reverse('admin:seminar_{}_change'.format(model_name), args=(self.id, ))
5 years ago
def verejne_url(self):
return None
@reversion.register(ignore_duplicates=True)
class Osoba(SeminarModelBase):
5 years ago
class Meta:
db_table = 'seminar_osoby'
verbose_name = 'Osoba'
verbose_name_plural = 'Osoby'
ordering = ['prijmeni','jmeno']
5 years ago
id = models.AutoField(primary_key = True)
jmeno = models.CharField('jméno', max_length=256)
prijmeni = models.CharField('příjmení', max_length=256)
prezdivka = models.CharField('přezdívka', max_length=256)
5 years ago
# User, pokud má na webu účet
user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True,
verbose_name='uživatel', on_delete=models.DO_NOTHING)
5 years ago
# Pohlaví. Že ho neznáme se snad nestane (a ušetří to práci při programování)
pohlavi_muz = models.BooleanField('pohlaví (muž)', default=False)
email = models.EmailField('e-mail', max_length=256, blank=True, default='')
5 years ago
telefon = models.CharField('telefon', max_length=256, blank=True, default='')
5 years ago
datum_narozeni = models.DateField('datum narození', blank=True, null=True)
5 years ago
# NULL dokud nedali souhlas
datum_souhlasu_udaje = models.DateField('datum souhlasu (údaje)', blank=True, null=True,
help_text='Datum souhlasu se zpracováním osobních údajů')
5 years ago
# NULL dokud nedali souhlas
datum_souhlasu_zasilani = models.DateField('datum souhlasu (spam)', blank=True, null=True,
help_text='Datum souhlasu se zasíláním MFF materiálů')
5 years ago
# Alespoň odhad (rok či i měsíc)
datum_registrace = models.DateField('datum registrace do semináře', default=timezone.now)
5 years ago
# Ulice může být i jen číslo
ulice = models.CharField('ulice', max_length=256, blank=True, default='')
mesto = models.CharField('město', max_length=256, blank=True, default='')
psc = models.CharField('PSČ', max_length=32, blank=True, default='')
5 years ago
# ISO 3166-1 dvojznakovy kod zeme velkym pismem (CZ, SK)
# Ekvivalentní s CharField(max_length=2, default='CZ', ...)
stat = CountryField('stát', default='CZ',
help_text='ISO 3166-1 kód země velkými písmeny (CZ, SK, ...)')
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k osobě (plain text)')
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})
# má OneToOneField nejvýše s:
# Resitel
# Prijemce
# Organizator
5 years ago
def plne_jmeno(self):
return '{} {}'.format(self.jmeno, self.prijmeni)
5 years ago
def inicial_krestni(self):
jmena = self.jmeno.split()
return " ".join(['{}.'.format(jmeno[0]) for jmeno in jmena])
5 years ago
def __str__(self):
return self.plne_jmeno()
#
# Mělo by být částečně vytaženo z Aesopa
# viz https://ovvp.mff.cuni.cz/wiki/aesop/export-skol.
#
@reversion.register(ignore_duplicates=True)
class Skola(SeminarModelBase):
class Meta:
db_table = 'seminar_skoly'
verbose_name = 'Škola'
verbose_name_plural = 'Školy'
ordering = ['mesto', 'nazev']
# Interní ID
id = models.AutoField(primary_key = True)
# Aesopi ID "izo:..." nebo "aesop:..."
# NULL znamená v exportu do aesopa "ufo"
aesop_id = models.CharField('Aesop ID', max_length=32, blank=True, default='',
help_text='Aesopi ID typu "izo:..." nebo "aesop:..."')
# IZO školy (jen české školy)
izo = models.CharField('IZO', max_length=32, blank=True,
help_text='IZO školy (jen české školy)')
# Celý název školy
nazev = models.CharField('název', max_length=256,
help_text='Celý název školy')
# Zkraceny nazev pro zobrazení ve výsledkovce, volitelné.
# Není v Aesopovi, musíme vytvářet sami.
kratky_nazev = models.CharField('zkrácený název', max_length=256, blank=True,
help_text="Zkrácený název pro zobrazení ve výsledkovce")
# Ulice může být jen číslo
ulice = models.CharField('ulice', max_length=256)
mesto = models.CharField('město', max_length=256)
psc = models.CharField('PSČ', max_length=32)
# ISO 3166-1 dvojznakovy kod zeme velkym pismem (CZ, SK)
# Ekvivalentní s CharField(max_length=2, default='CZ', ...)
stat = CountryField('stát', default='CZ',
help_text='ISO 3166-1 kód země velkými písmeny (CZ, SK, ...)')
# Jaké vzdělání škpla poskytuje?
je_zs = models.BooleanField('základní stupeň', default=True)
je_ss = models.BooleanField('střední stupeň', default=True)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka ke škole (plain text)')
kontaktni_osoba = models.ForeignKey(Osoba, verbose_name='Kontaktní osoba',
blank=True, null=True, on_delete=models.SET_NULL)
def __str__(self):
return '{}, {}, {}'.format(self.nazev, self.ulice, self.mesto)
class Prijemce(SeminarModelBase):
class Meta:
db_table = 'seminar_prijemce'
verbose_name = 'příjemce'
verbose_name_plural = 'příjemce'
# Interní ID
id = models.AutoField(primary_key = True)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k příemci čísel (plain text)')
osoba = models.OneToOneField(Osoba, verbose_name='komu', blank=False, null=False,
help_text='Které osobě či na jakou adresu se mají zasílat čísla',
on_delete=models.CASCADE)
# FIXME: možná chceme něco jako vazbu na osobu XOR školu a počet kusů k zaslání
# FIXME: a možná taky posílání na mail a možná taky přes něj chceme posílat i řešitelům
def __str__(self):
return self.osoba.plne_jmeno()
@reversion.register(ignore_duplicates=True)
class Resitel(SeminarModelBase):
class Meta:
db_table = 'seminar_resitele'
verbose_name = 'Řešitel'
verbose_name_plural = 'Řešitelé'
ordering = ['osoba']
# Interní ID
id = models.AutoField(primary_key = True)
osoba = models.OneToOneField(Osoba, blank=False, null=True, verbose_name='osoba',
on_delete=models.SET_NULL) # FIXME opravit po prvni migraci
skola = models.ForeignKey(Skola, blank=True, null=True, verbose_name='škola',
on_delete=models.SET_NULL)
# Očekávaný rok maturity a vyřazení z aktivních řešitelů
rok_maturity = models.IntegerField('rok maturity', blank=True, null=True)
ZASILAT_DOMU = 'domu'
ZASILAT_DO_SKOLY = 'do_skoly'
ZASILAT_NIKAM = 'nikam'
ZASILAT_CHOICES = [
(ZASILAT_DOMU, 'Domů'),
(ZASILAT_DO_SKOLY, 'Do školy'),
(ZASILAT_NIKAM, 'Nikam'),
]
zasilat = models.CharField('kam zasílat', max_length=32, choices=ZASILAT_CHOICES, blank=False, default=ZASILAT_DOMU)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k řešiteli (plain text)')
5 years ago
def export_row(self):
"Slovnik pro pouziti v AESOP exportu"
5 years ago
return {
'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',
5 years ago
}
5 years ago
def rocnik(self, rocnik):
"""Vrati skolni rocnik resitele pro zadany Rocnik.
Vraci '' pro neznamy rok maturity resitele, Z* pro ekvivalent ."""
if self.rok_maturity is None:
return ''
rozdil = 5 - (self.rok_maturity - rocnik.prvni_rok)
if rozdil >= 1:
return str(rozdil)
else:
return 'Z' + str(rozdil + 9)
def vsechny_body(self):
"Spočítá body odjakživa."
vsechna_reseni = self.reseni_set.all()
vsechna_hodnoceni = Hodnoceni.objects.filter(
reseni__in=vsechna_reseni)
return sum(h.body for h in list(vsechna_hodnoceni))
def get_titul(self):
"Vrati titul"
celkove_body = self.vsechny_body()
5 years ago
if celkove_body < 10:
return ''
elif celkove_body < 20:
return 'Bc.'
elif celkove_body < 50:
return 'Mgr.'
elif celkove_body < 100:
return 'Dr.'
elif celkove_body < 200:
return 'Doc.'
elif celkove_body < 500:
return 'Prof.'
else:
return 'Akad.'
def __str__(self):
return self.osoba.plne_jmeno()
@reversion.register(ignore_duplicates=True)
class Rocnik(SeminarModelBase):
5 years ago
class Meta:
db_table = 'seminar_rocniky'
verbose_name = 'Ročník'
verbose_name_plural = 'Ročníky'
5 years ago
ordering = ['-rocnik']
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
prvni_rok = models.IntegerField('první rok', db_index=True, unique=True)
rocnik = models.IntegerField('číslo ročníku', db_index=True, unique=True)
exportovat = models.BooleanField('export do AESOPa', db_column='exportovat', default=False,
help_text='Exportuje se jen podle tohoto flagu (ne veřejnosti),'
' a to jen čísla s veřejnou výsledkovkou')
# má OneToOneField s:
# RocnikNode
5 years ago
def __str__(self):
return '{} ({}/{})'.format(self.rocnik, self.prvni_rok, self.prvni_rok+1)
# Ročník v římských číslech
5 years ago
def roman(self):
return roman(int(self.rocnik))
5 years ago
def verejne(self):
return len(self.verejna_cisla()) > 0
verejne.boolean = True
verejne.short_description = 'Veřejný (jen dle čísel)'
5 years ago
def verejna_cisla(self):
vc = [c for c in self.cisla.all() if c.verejne()]
vc.sort(key=lambda c: c.poradi)
5 years ago
return vc
5 years ago
def posledni_verejne_cislo(self):
vc = self.verejna_cisla()
return vc[-1] if vc else None
5 years ago
def verejne_vysledkovky_cisla(self):
vc = list(self.cisla.filter(verejna_vysledkovka=True))
vc.sort(key=lambda c: c.poradi)
5 years ago
return vc
5 years ago
def posledni_zverejnena_vysledkovka_cislo(self):
vc = self.verejne_vysledkovky_cisla()
return vc[-1] if vc else None
5 years ago
def druhy_rok(self):
return self.prvni_rok + 1
5 years ago
def verejne_url(self):
return reverse('seminar_rocnik', kwargs={'rocnik': self.rocnik})
5 years ago
@classmethod
def cached_rocnik(cls, r_id):
name = 'rocnik_%s' % (r_id, )
c = cache.get(name)
if c is None:
c = cls.objects.get(id=r_id)
cache.set(name, c, 300)
return c
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
try:
self.rocniknode.save()
except ObjectDoesNotExist:
# Neexistující *Node nemá smysl aktualizovat.
pass
def cislo_pdf_filename(self, filename):
5 years ago
rocnik = str(self.rocnik.rocnik)
return os.path.join('cislo', 'pdf', rocnik, '{}-{}.pdf'.format(rocnik, self.poradi))
@reversion.register(ignore_duplicates=True)
class Cislo(SeminarModelBase):
5 years ago
class Meta:
db_table = 'seminar_cisla'
verbose_name = 'Číslo'
verbose_name_plural = 'Čísla'
ordering = ['-rocnik__rocnik', '-poradi']
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
rocnik = models.ForeignKey(Rocnik, verbose_name='ročník', related_name='cisla',
db_index=True,on_delete=models.PROTECT)
5 years ago
poradi = models.CharField('název čísla', max_length=32, db_index=True,
help_text='Většinou jen "1", vyjímečně "7-8", lexikograficky určuje pořadí v ročníku!')
5 years ago
datum_vydani = models.DateField('datum vydání', blank=True, null=True,
help_text='Datum vydání finální verze')
5 years ago
datum_deadline = models.DateField('datum deadline', blank=True, null=True,
help_text='Datum pro příjem řešení úloh zadaných v tomto čísle')
5 years ago
datum_deadline_soustredeni = models.DateField(
'datum deadline soustředění',
5 years ago
blank=True, null=True,
help_text='Datum pro příjem řešení pro účast na soustředění')
5 years ago
verejne_db = models.BooleanField('číslo zveřejněno',
db_column='verejne', default=False)
5 years ago
verejna_vysledkovka = models.BooleanField(
'zveřejněna výsledkovka',
5 years ago
default=False,
help_text='Je-li false u veřejného čísla, '
'není výsledkovka zatím veřejná.')
5 years ago
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k číslu (plain text)')
5 years ago
pdf = models.FileField('pdf', upload_to=cislo_pdf_filename, null=True, blank=True,
help_text='Pdf čísla, které si mohou řešitelé stáhnout')
5 years ago
# má OneToOneField s:
# CisloNode
5 years ago
def kod(self):
return '%s.%s' % (self.rocnik.rocnik, self.poradi)
kod.short_description = 'Kód čísla'
5 years ago
def __str__(self):
# Potenciální DB HOG, pokud by se ročník necachoval
r = Rocnik.cached_rocnik(self.rocnik_id)
return '{}.{}'.format(r.rocnik, self.poradi)
5 years ago
def verejne(self):
return self.verejne_db
verejne.boolean = True
def verejne_url(self):
return reverse('seminar_cislo', kwargs={'rocnik': self.rocnik.rocnik, 'cislo': self.poradi})
5 years ago
def nasledujici(self):
"Vrací None, pokud je toto poslední"
5 years ago
return self.relativni_v_rocniku(1)
def predchozi(self):
"Vrací None, pokud je toto první"
5 years ago
return self.relativni_v_rocniku(-1)
def relativni_v_rocniku(self, rel_index):
"Číslo o `index` dále v ročníku. None pokud neexistuje."
5 years ago
cs = self.rocnik.cisla.order_by('cislo').all()
i = list(cs).index(self) + rel_index
if (i < 0) or (i >= len(cs)):
return None
return cs[i]
@classmethod
def get(cls, rocnik, cislo):
try:
r = Rocnik.objects.get(rocnik=rocnik)
c = r.cisla.get(cislo=cislo)
except ObjectDoesNotExist:
return None
return c
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
try:
self.cislonode.save()
except ObjectDoesNotExist:
# Neexistující *Node nemá smysl aktualizovat.
pass
@reversion.register(ignore_duplicates=True)
class Organizator(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
osoba = models.OneToOneField(Osoba, verbose_name='osoba', related_name='org',
help_text='osobní údaje organizátora', null=True, blank=False,
on_delete=models.SET_NULL) #FIXME opravit po migraci
vytvoreno = models.DateTimeField(
'Vytvořeno',
default=timezone.now,
blank=True,
editable=False
)
organizuje_od = models.DateTimeField('Organizuje od', blank=True, null=True)
organizuje_do = models.DateTimeField('Organizuje do', blank=True, null=True)
studuje = models.CharField('Studium aj.', max_length = 256,
null = True, blank = True,
5 years ago
help_text="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',
null = True, blank = True)
skola = models.CharField('Škola, kterou studuje', max_length = 256, null=True, blank=True,
5 years ago
help_text="Š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.osoba.prezdivka:
return "{} '{}' {}".format(self.osoba.jmeno,
self.osoba.prezdivka,
self.osoba.prijmeni)
else:
return "{} {}".format(self.osoba.jmeno, self.osoba.prijmeni)
class Meta:
verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři'
@reversion.register(ignore_duplicates=True)
class Soustredeni(SeminarModelBase):
class Meta:
db_table = 'seminar_soustredeni'
verbose_name = 'Soustředění'
verbose_name_plural = 'Soustředění'
ordering = ['-rocnik__rocnik', '-datum_zacatku']
# Interní ID
id = models.AutoField(primary_key = True)
rocnik = models.ForeignKey(Rocnik, verbose_name='ročník', related_name='soustredeni',
on_delete=models.PROTECT)
datum_zacatku = models.DateField('datum začátku', blank=True, null=True,
help_text='První den soustředění')
datum_konce = models.DateField('datum konce', blank=True, null=True,
help_text='Poslední den soustředění')
verejne_db = models.BooleanField('soustředění zveřejněno', db_column='verejne', default=False)
misto = models.CharField('místo soustředění', max_length=256, blank=True, default='',
help_text='Místo (název obce, volitelně též objektu')
ucastnici = models.ManyToManyField(Resitel, verbose_name='účastníci soustředění',
help_text='Seznam účastníků soustředění', through='Soustredeni_Ucastnici')
organizatori = models.ManyToManyField(Organizator,
verbose_name='Organizátoři soustředění',
help_text='Seznam organizátorů soustředění',
through='Soustredeni_Organizatori')
text = models.TextField('text k soustředění (HTML)', blank=True, default='')
TYP_JARNI = 'jarni'
TYP_PODZIMNI = 'podzimni'
TYP_VIKEND = 'vikend'
TYP_CHOICES = [
(TYP_JARNI, 'Jarní soustředění'),
(TYP_PODZIMNI, 'Podzimní soustředění'),
(TYP_VIKEND, 'Víkendový sraz'),
]
typ = models.CharField('typ akce', max_length=16, choices=TYP_CHOICES, blank=False, default=TYP_PODZIMNI)
exportovat = models.BooleanField('export do AESOPa', db_column='exportovat', default=False,
help_text='Exportuje se jen podle tohoto flagu (ne veřejnosti)')
def __str__(self):
return '{} ({})'.format(self.misto, self.datum_zacatku)
def verejne(self):
return self.verejne_db
verejne.boolean = True
def verejne_url(self):
#return reverse('seminar_soustredeni', kwargs={'pk': self.id})
return reverse('seminar_seznam_soustredeni')
@reversion.register(ignore_duplicates=True)
# Pozor na následující řádek. *Nekrmit, asi kouše!*
class Problem(SeminarModelBase,PolymorphicModel):
5 years ago
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'
5 years ago
ordering = ['nazev']
# Interní ID
id = models.AutoField(primary_key = True)
# Název
nazev = models.CharField('název', max_length=256)
5 years ago
# 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)
5 years ago
STAV_NAVRH = 'navrh'
STAV_ZADANY = 'zadany'
STAV_VYRESENY = 'vyreseny'
5 years ago
STAV_SMAZANY = 'smazany'
STAV_CHOICES = [
(STAV_NAVRH, 'Návrh'),
(STAV_ZADANY, 'Zadaný'),
(STAV_VYRESENY, 'Vyřešený'),
(STAV_SMAZANY, 'Smazaný'),
5 years ago
]
stav = models.CharField('stav problému', max_length=32, choices=STAV_CHOICES, blank=False, default=STAV_NAVRH)
5 years ago
zamereni = TaggableManager(verbose_name='zaměření',
help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True)
5 years ago
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 ...')
5 years ago
autor = models.ForeignKey(Organizator, verbose_name='autor problému',
related_name='autor_problemu_%(class)s', null=True, blank=True,
on_delete=models.SET_NULL)
5 years ago
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)
5 years ago
opravovatele = models.ManyToManyField(Organizator, verbose_name='opravovatelé',
blank=True, related_name='opravovatele_%(class)s')
5 years ago
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')
5 years ago
vytvoreno = models.DateTimeField('vytvořeno', default=timezone.now, blank=True, editable=False)
5 years ago
def __str__(self):
return self.nazev
5 years ago
# Implicitini implementace, jednotlivé dědící třídy si přepíšou
5 years ago
def kod_v_rocniku(self):
if self.stav == 'zadany':
if self.nadproblem:
5 years ago
return self.nadproblem.kod_v_rocniku()+".{}".format(self.kod)
return str(self.kod)
return '<Není zadaný>'
5 years ago
def verejne(self):
return (self.cislo_zadani and self.cislo_zadani.verejne())
verejne.boolean = True
def verejne_url(self):
return reverse('seminar_problem', kwargs={'pk': self.id})
def admin_url(self):
if self.stav == Problem.STAV_ZADANY:
return reverse('admin:seminar_problemzadany_change', args=(self.id, ))
else:
return reverse('admin:seminar_problemnavrh_change', args=(self.id, ))
# FIXME - k úloze
5 years ago
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 ""
class Tema(Problem):
class Meta:
db_table = 'seminar_temata'
verbose_name = 'Téma'
verbose_name_plural = 'Témata'
TEMA_TEMA = 'tema'
TEMA_SERIAL = 'serial'
TEMA_CHOICES = [
(TEMA_TEMA, 'Téma'),
(TEMA_SERIAL, 'Seriál'),
]
tema_typ = models.CharField('Typ tématu', max_length=16, choices=TEMA_CHOICES,
blank=False, default=TEMA_TEMA)
rocnik = models.ForeignKey(Rocnik, verbose_name='ročník',blank=True, null=True,
on_delete=models.PROTECT)
def kod_v_rocniku(self):
if self.stav == 'zadany':
if self.nadproblem:
return self.nadproblem.kod_v_rocniku()+".t{}".format(self.kod)
return "t{}".format(self.kod)
return '<Není zadaný>'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
for tvcn in self_temavcislenode_set:
tvcn.save()
class Clanek(Problem):
class Meta:
db_table = 'seminar_clanky'
verbose_name = 'Článek'
verbose_name_plural = 'Články'
cislo = models.ForeignKey(Cislo, verbose_name='číslo', blank=True, null=True,
on_delete=models.PROTECT)
# má OneToOneField s:
# ClanekNode
def kod_v_rocniku(self):
if self.stav == 'zadany':
# Nemělo by být potřeba
# if self.nadproblem:
5 years ago
# return self.nadproblem.kod_v_rocniku()+".c{}".format(self.kod)
return "c{}".format(self.kod)
return '<Není zadaný>'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
try:
self.claneknode.save()
except ObjectDoesNotExist:
# Neexistující *Node nemá smysl aktualizovat.
pass
class Text(SeminarModelBase):
class Meta:
db_table = 'seminar_texty'
verbose_name = 'text'
verbose_name_plural = 'texty'
na_web = models.TextField('text na web', blank=True,
help_text='Text ke zveřejnění na webu')
do_cisla = models.TextField('text do čísla', blank=True,
help_text='Text ke zveřejnění v čísle')
# má OneToOneField s:
# Reseni (je u něj jako reseni_cele)
# obrázky mají návaznost opačným směrem (vazba z druhé strany)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
for tn in self.textnode_set:
tn.save()
class Uloha(Problem):
class Meta:
db_table = 'seminar_ulohy'
verbose_name = 'Úloha'
verbose_name_plural = 'Úlohy'
cislo_zadani = models.ForeignKey(Cislo, verbose_name='číslo zadání', blank=True,
null=True, related_name='zadane_ulohy', on_delete=models.PROTECT)
cislo_deadline = models.ForeignKey(Cislo, verbose_name='číslo deadlinu', blank=True,
null=True, related_name='deadlinove_ulohy', on_delete=models.PROTECT)
cislo_reseni = models.ForeignKey(Cislo, verbose_name='číslo řešení', blank=True,
null=True, related_name='resene_ulohy',
help_text='Číslo s řešením úlohy, jen pro úlohy',
on_delete=models.PROTECT)
max_body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='maximum bodů',
blank=True, null=True)
# má OneToOneField s:
# UlohaZadaniNode
# UlohaVzorakNode
def kod_v_rocniku(self):
if self.stav == 'zadany':
name="{}.u{}".format(self.cislo_zadani.poradi,self.kod)
if self.nadproblem:
return self.nadproblem.kod_v_rocniku()+name
return name
return '<Není zadaný>'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
try:
self.ulohazadaninode.save()
except ObjectDoesNotExist:
# Neexistující *Node nemá smysl aktualizovat.
pass
try:
self.ulohavzoraknode.save()
except ObjectDoesNotExist:
# Neexistující *Node nemá smysl aktualizovat.
pass
@reversion.register(ignore_duplicates=True)
class Reseni(SeminarModelBase):
5 years ago
class Meta:
db_table = 'seminar_reseni'
verbose_name = 'Řešení'
verbose_name_plural = 'Řešení'
#ordering = ['-problem', 'resitele'] # FIXME: Takhle to chceme, ale nefunguje to.
ordering = ['-cas_doruceni']
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
# Ke každé dvojici řešní a problém existuje nanejvýš jedno hodnocení, doplnění vazby.
problem = models.ManyToManyField(Problem, verbose_name='problém', help_text='Problém',
through='Hodnoceni')
resitele = models.ManyToManyField(Resitel, verbose_name='autoři řešení',
help_text='Seznam autorů řešení', through='Reseni_Resitele')
cas_doruceni = models.DateTimeField('čas_doručení', default=timezone.now, blank=True)
5 years ago
FORMA_PAPIR = 'papir'
FORMA_EMAIL = 'email'
FORMA_UPLOAD = 'upload'
FORMA_CHOICES = [
(FORMA_PAPIR, 'Papírové řešení'),
(FORMA_EMAIL, 'Emailem'),
(FORMA_UPLOAD, 'Upload přes web'),
5 years ago
]
forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False,
default=FORMA_EMAIL)
text_cely = models.OneToOneField(Text, verbose_name='Plná verze textu řešení',
blank=True, null=True, related_name="reseni_cely_set",
on_delete=models.SET_NULL)
text_zkraceny = models.ManyToManyField(Text, verbose_name='zkrácené verze řešení',
help_text='Seznam úryvků z řešení',related_name="reseni_zkraceny_set")
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k řešení (plain text)')
zverejneno = models.BooleanField('řešení zveřejněno', default=False,
help_text='Udává, zda je řešení zveřejněno')
# má OneToOneField s:
# Konfera
5 years ago
def __str__(self):
return "{}: {}".format(self.resitel.osoba.plne_jmeno(), self.problem.nazev)
5 years ago
# NOTE: Potenciální DB HOG (bez select_related)
## 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 = 'Hodnocení'
verbose_name_plural = 'Hodnocení'
# Interní ID
id = models.AutoField(primary_key = True)
body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name='body',
blank=False, null=False)
cislo_body = models.ForeignKey(Cislo, verbose_name='číslo pro body',
related_name='hodnoceni', blank=False, null=False, on_delete=models.PROTECT)
reseni = models.ForeignKey(Reseni, verbose_name='řešení', on_delete=models.CASCADE)
problem = models.ForeignKey(Problem, verbose_name='problém', on_delete=models.PROTECT)
def __str__(self):
return "{}, {}, {}".format(self.problem, self.reseni, self.body)
## 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.
##
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)
)
@reversion.register(ignore_duplicates=True)
class PrilohaReseni(SeminarModelBase):
5 years ago
class Meta:
db_table = 'seminar_priloha_reseni'
verbose_name = 'Příloha řešení'
verbose_name_plural = 'Přílohy řešení'
ordering = ['reseni', 'vytvoreno']
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
reseni = models.ForeignKey(Reseni, verbose_name='řešení', related_name='prilohy',
on_delete=models.CASCADE)
vytvoreno = models.DateTimeField('vytvořeno', default=timezone.now, blank=True, editable=False)
soubor = models.FileField('soubor', upload_to = generate_filename)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k příloze řešení (plain text), např. o původu')
5 years ago
def __str__(self):
return self.soubor
class Pohadka(SeminarModelBase):
5 years ago
"""Kus pohádky před/za úlohou v čísle"""
5 years ago
class Meta:
db_table = 'seminar_pohadky'
verbose_name = 'Pohádka'
verbose_name_plural = 'Pohádky'
ordering = ['vytvoreno']
5 years ago
# Interní ID
id = models.AutoField(primary_key=True)
5 years ago
autor = models.ForeignKey(
Organizator,
5 years ago
verbose_name="Autor pohádky",
5 years ago
# Při nahrávání z TeXu není vyplnění vyžadováno, v adminu je
null=True,
blank=False,
on_delete=models.SET_NULL
5 years ago
)
vytvoreno = models.DateTimeField(
'Vytvořeno',
5 years ago
default=timezone.now,
blank=True,
editable=False
)
# má OneToOneField s:
# PohadkaNode
5 years ago
def __str__(self):
uryvek = self.text if len(self.text) < 50 else self.text[:(50-3)]+"..."
return uryvek
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
try:
self.pohadkanode.save()
except ObjectDoesNotExist:
# Neexistující *Node nemá smysl aktualizovat.
pass
@reversion.register(ignore_duplicates=True)
class Soustredeni_Ucastnici(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
5 years ago
class Meta:
db_table = 'seminar_soustredeni_ucastnici'
verbose_name = 'Účast na soustředění'
verbose_name_plural = 'Účasti na soustředění'
5 years ago
ordering = ['soustredeni', 'resitel']
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT)
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
on_delete=models.PROTECT)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k účasti (plain text)')
5 years ago
def __str__(self):
return '{} na {}'.format(self.resitel, self.soustredeni)
5 years ago
# NOTE: Poteciální DB HOG bez select_related
@reversion.register(ignore_duplicates=True)
class Soustredeni_Organizatori(SeminarModelBase):
# zmena dedicnosti z models.Model na SeminarModelBase, potencialni vznik bugu
5 years ago
class Meta:
db_table = 'seminar_soustredeni_organizatori'
verbose_name = 'Účast organizátorů na soustředění'
verbose_name_plural = 'Účasti organizátorů na soustředění'
5 years ago
ordering = ['soustredeni', 'organizator']
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
organizator = models.ForeignKey(Organizator, verbose_name='organizátor',
on_delete=models.PROTECT)
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
on_delete=models.PROTECT)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k účasti organizátora (plain text)')
5 years ago
def __str__(self):
return '{} na {}'.format(self.organizator, self.soustredeni)
5 years ago
# NOTE: Poteciální DB HOG bez select_related
@reversion.register(ignore_duplicates=True)
class Konfera(models.Model):
5 years ago
class Meta:
db_table = 'seminar_konfera'
verbose_name = 'Konfera'
verbose_name_plural = 'Konfery'
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
nazev = models.CharField('název konfery', max_length=100, help_text = 'Název konfery')
anotace = models.TextField('anotace', blank=True,
help_text='Popis, o čem bude konfera.')
abstrakt = models.TextField('abstrakt', blank=True,
help_text='Abstrakt konfery tak, jak byl uveden ve sborníku')
organizator = models.ForeignKey(Organizator, verbose_name='organizátor', related_name='konfery',
5 years ago
on_delete = models.SET_NULL, null=True)
# FIXME: Umíme omezit jen na účastníky daného soustřeďka?
ucastnici = models.ManyToManyField(Resitel, verbose_name='účastníci konfery',
help_text='Seznam účastníků konfery', through='Konfery_Ucastnici')
soustredeni = models.ForeignKey(Soustredeni, verbose_name='soustředění',
related_name='konfery', on_delete = models.SET_NULL, null=True)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka ke konfeře(plain text)')
# Jedno reseni se vztahuje nejvyse k jedne konfere
reseni = models.OneToOneField(Reseni, verbose_name='článek ke konfeře', related_name='konfery',
help_text='Účastnický přípěvek o konfeře', on_delete = models.SET_NULL,
null=True, blank=True)
5 years ago
TYP_VELETRH = 'veletrh'
TYP_PREZENTACE = 'prezentace'
TYP_CHOICES = [
(TYP_VELETRH, 'Veletrh (postery)'),
(TYP_PREZENTACE, 'Prezentace (přednáška)'),
5 years ago
]
typ_prezentace = models.CharField('typ prezentace', max_length=16, choices=TYP_CHOICES,
blank=False, default=TYP_VELETRH)
prezentace = models.FileField('prezentace',help_text = 'Prezentace nebo fotka posteru',
5 years ago
upload_to = generate_filename_konfera, blank=True)
materialy = models.FileField('materialy',
help_text = 'Další materiály ke konfeře zabalené do jednoho souboru',
5 years ago
upload_to = generate_filename_konfera, blank=True)
# má OneToOneField s:
# KonferaNode
5 years ago
def __str__(self):
return "{}: ({})".format(self.nazev, self.soustredeni)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# *Node.save() aktualizuje název *Nodu.
try:
self.konferanode.save()
except ObjectDoesNotExist:
# Neexistující *Node nemá smysl aktualizovat.
pass
# Vazebna tabulka. Mozna se generuje automaticky.
@reversion.register(ignore_duplicates=True)
class Reseni_Resitele(models.Model):
class Meta:
db_table = 'seminar_reseni_resitele'
verbose_name = 'Řešení řešitelů'
verbose_name_plural = 'Řešení řešitelů'
ordering = ['reseni', 'resitele']
# Interní ID
id = models.AutoField(primary_key = True)
resitele = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT)
reseni = models.ForeignKey(Reseni, verbose_name='řešení', on_delete=models.CASCADE)
# podil - jakou merou se ktery resitel podilel na danem reseni
# - pouziti v budoucnu, pokud by resitele nemeli dostat vsichni stejne bodu za spolecne reseni
def __str__(self):
return '{} od {}'.format(self.reseni, self.resitel)
# NOTE: Poteciální DB HOG bez select_related
@reversion.register(ignore_duplicates=True)
class Konfery_Ucastnici(models.Model):
5 years ago
class Meta:
db_table = 'seminar_konfery_ucastnici'
verbose_name = 'Účast na konfeře'
verbose_name_plural = 'Účasti na konfeře'
5 years ago
ordering = ['konfera', 'resitel']
5 years ago
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name='řešitel', on_delete=models.PROTECT)
konfera = models.ForeignKey(Konfera, verbose_name='konfera', on_delete=models.CASCADE)
poznamka = models.TextField('neveřejná poznámka', blank=True,
help_text='Neveřejná poznámka k účasti (plain text)')
5 years ago
def __str__(self):
return '{} na {}'.format(self.resitel, self.konfera)
5 years ago
# NOTE: Poteciální DB HOG bez select_related
class Obrazek(SeminarModelBase):
5 years ago
class Meta:
db_table = 'seminar_obrazky'
verbose_name = 'obrázek'
verbose_name_plural = 'obrázky'
# Interní ID
id = models.AutoField(primary_key = True)
na_web = models.ImageField('obrázek na web', upload_to='obrazky/%Y/%m/%d/',
null=True, blank=True)
text = models.ForeignKey(Text, verbose_name='text',
help_text='text, ve kterém se obrázek vyskytuje',
null=False, blank=False, on_delete=models.CASCADE)
do_cisla_barevny = models.FileField('barevný obrázek do čísla',
help_text = 'Barevná verze obrázku do čísla',
upload_to = 'obrazky/%Y/%m/%d/', blank=True, null=True)
do_cisla_cernobily = models.FileField('černobílý obrázek do čísla',
help_text = 'Černobílá verze obrázku do čísla',
upload_to = 'obrazky/%Y/%m/%d/', blank=True, null=True)
class TreeNode(PolymorphicModel):
class Meta:
db_table = "seminar_nodes_treenode"
verbose_name = "TreeNode"
verbose_name_plural = "TreeNody"
5 years ago
# TODO: Nechceme radši jako root vyžadovat přímo RocnikNode?
root = models.ForeignKey('TreeNode',
related_name="potomci_set",
null = True,
blank = False,
on_delete = models.SET_NULL, # Vrcholy s null kořenem jsou sirotci bez ročníku
verbose_name="kořen stromu")
first_child = models.ForeignKey('TreeNode',
null = True,
blank = True,
on_delete=models.SET_NULL,
verbose_name="první potomek")
succ = models.OneToOneField('TreeNode',
related_name="prev",
null = True,
blank = True,
on_delete=models.SET_NULL,
verbose_name="další element na stejné úrovni")
nazev = models.TextField("název tohoto node",
help_text = "Tento název se zobrazuje v nabídkách pro výběr vhodného TreeNode",
blank=False, null=True)
def print_tree(self,indent=0):
print("{}TreeNode({})".format(" "*indent,self.id))
if self.first_child:
self.first_child.print_tree(indent=indent+2)
if self.succ:
self.succ.print_tree(indent=indent)
def __str__(self):
5 years ago
if self.nazev:
return self.nazev
else:
#TODO: logování
return "Nepojmenovaný Treenode"
def save(self, *args, **kwargs):
self.aktualizuj_nazev()
super().save(*args, **kwargs)
class RocnikNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_rocnik'
verbose_name = 'Ročník (Node)'
verbose_name_plural = 'Ročníky (Node)'
rocnik = models.OneToOneField(Rocnik,
on_delete = models.PROTECT, # Pokud chci mazat ročník, musím si Node pořešit ručně
verbose_name = "ročník")
def aktualizuj_nazev(self):
self.nazev = "RocnikNode: "+str(self.rocnik)
class CisloNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_cislo'
verbose_name = 'Číslo (Node)'
verbose_name_plural = 'Čísla (Node)'
cislo = models.OneToOneField(Cislo,
on_delete = models.PROTECT, # Pokud chci mazat číslo, musím si Node pořešit ručně
verbose_name = "číslo")
def aktualizuj_nazev(self):
self.nazev = "CisloNode: "+str(self.cislo)
class MezicisloNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_mezicislo'
verbose_name = 'Mezičíslo (Node)'
verbose_name_plural = 'Mezičísla (Node)'
def aktualizuj_nazev(self):
if self.prev:
if (self.prev.get_real_instance_class() != CisloNode and
self.prev.get_real_instance_class() != MezicisloNode):
raise ValueError("Předchůdce není číslo!")
posledni = self.prev.cislo
self.nazev = "MezicisloNode: Mezičíslo po čísle"+str(posledni)
elif self.root:
if self.root.get_real_instance_class() != RocnikNode:
raise ValueError("Kořen stromu není ročník!")
rocnik = self.root.rocnik
self.nazev = "MezicisloNode: První mezičíslo ročníku "+str(rocnik)
else:
print("!!!!! Nějaké neidentifikované mezičíslo !!!!!")
self.nazev = "MezicisloNode: Neidentifikovatelné mezičíslo!"
class TemaVCisleNode(TreeNode):
""" Obsahuje příspěvky k tématu v daném čísle """
class Meta:
db_table = 'seminar_nodes_temavcisle'
verbose_name = 'Téma v čísle (Node)'
verbose_name_plural = 'Témata v čísle (Node)'
tema = models.ForeignKey(Tema,
on_delete=models.PROTECT, # Pokud chci mazat téma, musím si Node pořešit ručně
verbose_name = "téma v čísle")
def aktualizuj_nazev(self):
self.nazev = "TemaVCisleNode: "+str(self.tema)
class KonferaNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_konfera'
verbose_name = 'Konfera (Node)'
verbose_name_plural = 'Konfery (Node)'
konfera = models.OneToOneField(Konfera,
on_delete=models.PROTECT, # Pokud chci mazat téma, musím si Node pořešit ručně
verbose_name = "konfera",
null=True,
blank=False)
def aktualizuj_nazev(self):
self.nazev = "KonferaNode: "+str(self.konfera)
class ClanekNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_clanek'
verbose_name = 'Článek (Node)'
verbose_name_plural = 'Články (Node)'
clanek = models.OneToOneField(Clanek,
on_delete=models.PROTECT, # Pokud chci mazat téma, musím si Node pořešit ručně
verbose_name = "článek",
null=True,
blank=False)
def aktualizuj_nazev(self):
self.nazev = "ClanekNode: "+str(self.clanek)
class UlohaZadaniNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_uloha_zadani'
verbose_name = 'Zadání úlohy (Node)'
verbose_name_plural = 'Zadání úloh (Node)'
uloha = models.OneToOneField(Uloha,
on_delete=models.PROTECT, # Pokud chci mazat téma, musím si Node pořešit ručně
verbose_name = "úloha",
null=True,
blank=False)
def aktualizuj_nazev(self):
self.nazev = "UlohaZadaniNode: "+str(self.uloha)
class PohadkaNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_pohadka'
verbose_name = 'Pohádka (Node)'
verbose_name_plural = 'Pohádky (Node)'
pohadka = models.OneToOneField(Pohadka,
on_delete=models.PROTECT, # Pokud chci mazat pohádku, musím si Node pořešit ručně
verbose_name = "pohádka",
)
def aktualizuj_nazev(self):
self.nazev = "PohadkaNode: "+str(self.pohadka)
class UlohaVzorakNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_uloha_vzorak'
verbose_name = 'Vzorák úlohy (Node)'
verbose_name_plural = 'Vzoráky úloh (Node)'
uloha = models.OneToOneField(Uloha,
on_delete=models.PROTECT, # Pokud chci mazat téma, musím si Node pořešit ručně
verbose_name = "úloha",
null=True,
blank=False)
def aktualizuj_nazev(self):
self.nazev = "UlohaVzorakNode: "+str(self.uloha)
class TextNode(TreeNode):
class Meta:
db_table = 'seminar_nodes_obsah'
verbose_name = 'Text (Node)'
verbose_name_plural = 'Text (Node)'
text = models.ForeignKey(Text,
on_delete=models.PROTECT,
verbose_name = 'text')
def aktualizuj_nazev(self):
self.nazev = "TextNode: "+str(self.text)
## FIXME: Logiku přesunout do views.
#class VysledkyBase(SeminarModelBase):
#
# class Meta:
# verbose_name = 'Řádek výsledkovky'
# verbose_name_plural = 'Řádky výsledkovky'
# ordering = ['body']
# abstract = True
# managed = False
#
# dummy_id = models.CharField('dummy ID pro view', max_length=32, primary_key=True,
# db_column='id')
#
# cislo = models.ForeignKey(Cislo, verbose_name='číslo pro body', db_column='cislo_id',
# on_delete=models.DO_NOTHING)
#
# resitel = models.ForeignKey(Resitel, verbose_name='řešitel', db_column='resitel_id',
# on_delete=models.DO_NOTHING)
#
5 years ago
# body = models.DecimalField(max_digits=8, decimal_places=1, db_column='body',
# verbose_name='body za číslo')
#
# def __str__(self):
5 years ago
# return "%s: %sb (%s)".format(self.resitel.plne_jmeno(), self.body,
# str(self.poradi))
# # NOTE: DB zatez pri vypisu (ale nepouzivany)
## 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='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='body do čísla (i minulé ročníky)')
#
#
## FIXME: Logiku přesunout do views.
#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='body celkem do čísla včetně minulých ročníků')
#
# def __str__(self):
# # NOTE: DB HOG (ale nepouzivany)
# return "%s: %sb / %sb (do %s)" % (self.resitel.plne_jmeno(), self.body, self.body_celkem, str(self.poradi))
##mozna potreba upravit
@reversion.register(ignore_duplicates=True)
class Nastaveni(SingletonModel):
5 years ago
class Meta:
db_table = 'seminar_nastaveni'
verbose_name = 'Nastavení semináře'
aktualni_rocnik = models.ForeignKey(Rocnik, verbose_name='aktuální ročník',
null=False, on_delete=models.PROTECT)
aktualni_cislo = models.ForeignKey(Cislo, verbose_name='poslední vydané číslo',
null=False, on_delete=models.PROTECT)
5 years ago
def __str__(self):
return 'Nastavení semináře'
5 years ago
def admin_url(self):
return reverse('admin:seminar_nastaveni_change', args=(self.id, ))
def verejne(self):
return False
@reversion.register(ignore_duplicates=True)
class Novinky(models.Model):
class Meta:
verbose_name = 'Novinka'
verbose_name_plural = 'Novinky'
ordering = ['-datum']
5 years ago
datum = models.DateField(auto_now_add=True)
5 years ago
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)
5 years ago
obrazek_maly = ImageSpecField(source='obrazek',
processors=[
ResizeToFit(350, 200, upscale=False)
],
options={'quality': 95})
autor = models.ForeignKey(Organizator, verbose_name='Autor novinky', null=True,
on_delete=models.SET_NULL)
zverejneno = models.BooleanField('Zveřejněno', default=False)
5 years ago
def __str__(self):
if self.text:
return '[' + str(self.datum) + '] ' + self.text[0:50]
else:
return '[' + str(self.datum) + '] '