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.
 
 
 
 
 
 

1064 lines
38 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 python_2_unicode_compatible
from django.utils.encoding import force_unicode
from django.utils.text import slugify
from django.core.urlresolvers 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
class SeminarModelBase(models.Model):
class Meta:
abstract = True
def verejne(self):
return False
def get_absolute_url(self):
return self.verejne_url() # TODO "absolute"
def admin_url(self):
model_name = self.__class__.__name__.lower()
return reverse('admin:seminar_%s_change'%(model_name, ), args=(self.id, ))
def verejne_url(self):
return None
#
# 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)
@python_2_unicode_compatible
class Skola(SeminarModelBase):
class Meta:
db_table = 'seminar_skoly'
verbose_name = u'Škola'
verbose_name_plural = u'Š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(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)')
# Celý název školy
nazev = models.CharField(u'název', max_length=256,
help_text=u'Celý název školy')
# Zkraceny nazev pro zobrazení ve výsledkovce, volitelné.
# Není v Aesopovi, musíme vytvářet sami.
kratky_nazev = models.CharField(u'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(u'ulice', max_length=256)
mesto = models.CharField(u'město', max_length=256)
psc = models.CharField(u'PSČ', max_length=32)
# ISO 3166-1 dvojznakovy kod zeme velkym pismem (CZ, SK)
# Ekvivalentní s CharField(max_length=2, default='CZ', ...)
stat = CountryField(u'stát', default='CZ',
help_text=u'ISO 3166-1 kód země velkými písmeny (CZ, SK, ...)')
# Jaké vzdělání škpla poskytuje?
je_zs = models.BooleanField(u'základní stupeň', default=True)
je_ss = models.BooleanField(u'střední stupeň', default=True)
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
help_text=u'Neveřejná poznámka ke škole (plain text)')
def __str__(self):
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 Meta:
db_table = 'seminar_resitele'
verbose_name = u'Řešitel'
verbose_name_plural = u'Řešitelé'
ordering = ['prijmeni', 'jmeno']
# Interní ID
id = models.AutoField(primary_key = True)
jmeno = models.CharField(u'jméno', max_length=256)
prijmeni = models.CharField(u'příjmení', 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='')
datum_narozeni = models.DateField(u'datum narození', blank=True, null=True)
# NULL dokud nedali souhlas
datum_souhlasu_udaje = models.DateField(u'datum souhlasu (údaje)', blank=True, null=True,
help_text=u'Datum souhlasu se zpracováním osobních údajů')
# NULL dokud nedali souhlas
datum_souhlasu_zasilani = models.DateField(u'datum souhlasu (spam)', blank=True, null=True,
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)
# Ulice může být i jen číslo
ulice = models.CharField(u'ulice', max_length=256, blank=True, default='')
mesto = models.CharField(u'město', max_length=256, blank=True, default='')
psc = models.CharField(u'PSČ', max_length=32, blank=True, default='')
# ISO 3166-1 dvojznakovy kod zeme velkym pismem (CZ, SK)
# Ekvivalentní s CharField(max_length=2, default='CZ', ...)
stat = CountryField(u'stát', default='CZ',
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)')
# 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')
def plne_jmeno(self):
return force_unicode(u'%s %s' % (self.jmeno, self.prijmeni))
def inicial_krestni(self):
return force_unicode(u'%s.' % (self.jmeno[0]))
def __str__(self):
return force_unicode(self.plne_jmeno())
def export_row(self):
"Slovnik pro pouziti v OVVP (OPMK) 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',
}
def rocnik(self, rocnik):
"""Vrati skolni rocnik resitele pro zadany Rocnik.
Vraci '' pro neznamy rok maturity resitele, Z* pro ekvivalent ZŠ."""
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 get_titul(self, celkove_body):
"Vrati titul podle zadaneho poctu bodu."
# Tituly na produkci zrušeny.
return ''
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.'
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Rocnik(SeminarModelBase):
class Meta:
db_table = 'seminar_rocniky'
verbose_name = u'Ročník'
verbose_name_plural = u'Ročníky'
ordering = ['-rocnik']
# Interní ID
id = models.AutoField(primary_key = True)
prvni_rok = models.IntegerField(u'první rok', db_index=True, unique=True)
rocnik = models.IntegerField(u'číslo ročníku', db_index=True, unique=True)
exportovat = models.BooleanField(u'export do AESOPa', db_column='exportovat', default=False,
help_text=u'Exportuje se jen podle tohoto flagu (ne veřejnosti), a to jen čísla s veřejnou výsledkovkou')
def __str__(self):
return force_unicode(u'%s (%d/%d)' % (self.rocnik, self.prvni_rok, self.prvni_rok+1))
def roman(self):
return force_unicode(roman(int(self.rocnik)))
def verejne(self):
return len(self.verejna_cisla()) > 0
verejne.boolean = True
verejne.short_description = u'Veřejný (jen dle čísel)'
def verejna_cisla(self):
vc = [c for c in self.cisla.all() if c.verejne()]
vc.sort(key=lambda c: c.cislo)
return vc
def posledni_verejne_cislo(self):
vc = self.verejna_cisla()
return vc[-1] if vc else None
def verejne_vysledkovky_cisla(self):
vc = list(self.cisla.filter(verejna_vysledkovka=True))
vc.sort(key=lambda c: c.cislo)
return vc
def posledni_zverejnena_vysledkovka_cislo(self):
vc = self.verejne_vysledkovky_cisla()
return vc[-1] if vc else None
def druhy_rok(self):
return self.prvni_rok + 1
def verejne_url(self):
return reverse('seminar_rocnik', kwargs={'rocnik': self.rocnik})
@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 cislo_pdf_filename(self, filename):
rocnik = str(self.rocnik.rocnik)
return os.path.join('cislo', 'pdf', rocnik, '{}-{}.pdf'.format(rocnik, self.cislo))
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Cislo(SeminarModelBase):
class Meta:
db_table = 'seminar_cisla'
verbose_name = u'Číslo'
verbose_name_plural = u'Čísla'
ordering = ['-rocnik__rocnik', '-cislo']
# Interní ID
id = models.AutoField(primary_key = True)
rocnik = models.ForeignKey(Rocnik, verbose_name=u'ročník', related_name='cisla', db_index=True)
cislo = models.CharField(u'název čísla', max_length=32, db_index=True,
help_text=u'Většinou jen "1", vyjímečně "7-8", lexikograficky určuje pořadí v ročníku!')
datum_vydani = models.DateField(u'datum vydání', blank=True, null=True,
help_text=u'Datum vydání finální verze')
datum_deadline = models.DateField(u'datum deadline', blank=True, null=True,
help_text=u'Datum pro příjem řešení úloh zadaných v tomto čísle')
datum_deadline_soustredeni = models.DateField(
u'datum deadline soustředění',
blank=True, null=True,
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)
verejna_vysledkovka = models.BooleanField(
u'zveřejněna výsledkovka',
default=False,
help_text=u'Je-li false u veřejného čísla,\
není výsledkovka zatím veřejná.')
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
help_text=u'Neveřejná poznámka k číslu (plain text)')
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)
kod.short_description = u'Kód čísla'
def __str__(self):
# Potenciální DB HOG, pokud by se ročník necachoval
r = Rocnik.cached_rocnik(self.rocnik_id)
return force_unicode(u'%s.%s' % (r.rocnik, self.cislo, ))
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.cislo})
def nasledujici(self):
u"Vrací None, pokud je toto poslední"
return self.relativni_v_rocniku(1)
def predchozi(self):
u"Vrací None, pokud je toto první"
return self.relativni_v_rocniku(-1)
def relativni_v_rocniku(self, rel_index):
u"Číslo o `index` dále v ročníku. None pokud neexistuje."
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
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Problem(SeminarModelBase):
class Meta:
db_table = 'seminar_problemy'
verbose_name = u'Problém'
verbose_name_plural = u'Problémy'
ordering = ['nazev']
# Interní ID
id = models.AutoField(primary_key = True)
# 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)
STAV_NAVRH = 'navrh'
STAV_ZADANY = 'zadany'
STAV_SMAZANY = 'smazany'
STAV_CHOICES = [
(STAV_NAVRH, u'Návrh'),
(STAV_ZADANY, u'Zadaný'),
(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,
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(settings.AUTH_USER_MODEL, verbose_name=u'autor problému', related_name='autor_uloh', null=True, blank=True)
opravovatel = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=u'opravovatel', null=True, blank=True,
related_name='opravovatel_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)
# 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, ))
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)
return u'<Není zadaný>'
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
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, ))
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 u"({}\u2009b)".format(pocet_bodu) if self.body else ""
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Reseni(SeminarModelBase):
class Meta:
db_table = 'seminar_reseni'
verbose_name = u'Řešení'
verbose_name_plural = u'Řešení'
ordering = ['problem_id', 'resitel__prijmeni', 'resitel__jmeno',]
# 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')
body = models.DecimalField(max_digits=8, decimal_places=1, verbose_name=u'body', blank=True, null=True)
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)
FORMA_PAPIR = 'papir'
FORMA_EMAIL = 'email'
FORMA_UPLOAD = 'upload'
FORMA_CHOICES = [
(FORMA_PAPIR, u'Papírové řešení'),
(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)
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
help_text=u'Neveřejná poznámka k řešení (plain text)')
def __str__(self):
return force_unicode(u"%s: %s (%sb)" % (self.resitel.plne_jmeno(), self.problem.nazev, self.body))
# 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)
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)
@python_2_unicode_compatible
class PrilohaReseni(SeminarModelBase):
class Meta:
db_table = 'seminar_priloha_reseni'
verbose_name = u'Příloha řešení'
verbose_name_plural = u'Přílohy řešení'
ordering = ['reseni', 'timestamp']
# Interní ID
id = models.AutoField(primary_key = True)
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)
soubor = models.FileField(u'soubor', upload_to = generate_filename)
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
help_text=u'Neveřejná poznámka k příloze řešení (plain text), např. o původu')
def __str__(self):
return force_unicode(self.soubor)
@python_2_unicode_compatible
class Pohadka(SeminarModelBase):
u"""Kus pohádky před/za úlohou v čísle"""
class Meta:
db_table = 'seminar_pohadky'
verbose_name = u'Pohádka'
verbose_name_plural = u'Pohádky'
ordering = ['uloha__cislo_zadani', 'uloha__kod', '-pred']
# Interní ID
id = models.AutoField(primary_key=True)
text = models.TextField(u'Text pohádky')
uloha = models.ForeignKey(
Problem,
verbose_name=u'Úloha',
related_name='pohadky'
)
# Kusů pohádky je v čísle obvykle o 1 více, než úloh. Jeden bude za úlohou
# místo před ní.
pred = models.BooleanField(u'Před úlohou', default=True)
autor = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name="Autor pohádky",
# Při nahrávání z TeXu není vyplnění vyžadováno, v adminu je
null=True,
blank=False
)
timestamp = models.DateTimeField(
u'Vytvořeno',
default=timezone.now,
blank=True,
editable=False
)
def __str__(self):
uryvek = self.text if len(self.text) < (50-3) else self.text[:50]+"..."
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?')
class Meta:
verbose_name = 'Příspěvek k problému'
verbose_name_plural = 'Příspěvky k problémům'
def __unicode__(self):
if self.reseni:
return force_unicode(self.nazev) + ' (' + \
force_unicode(self.reseni.resitel) + ') <Problem: ' + \
force_unicode(self.problem) + '>'
else:
return force_unicode(self.nazev) + ' <Problem: ' + \
force_unicode(self.problem) + '>'
@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', "
"'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)
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})
def __str__(self):
if self.prezdivka:
return u"%s '%s' %s" % (self.user.first_name,
self.prezdivka,
self.user.last_name)
else:
return u"%s %s" % (self.user.first_name, self.user.last_name)
class Meta:
verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři'
# Řadí aktivní orgy na začátek, pod tím v pořadí od nejstarších neaktivní orgy.
# TODO: Chtěl bych spíš mít nejstarší orgy dole.
# TODO: Zohledňovat přezdívky?
# TODO: Sjednotit s tím, jak se řadí organizátoři v seznau orgů na webu
ordering = ['-organizuje_do_roku', 'user__first_name', 'user__last_name']
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Soustredeni(SeminarModelBase):
class Meta:
db_table = 'seminar_soustredeni'
verbose_name = u'Soustředění'
verbose_name_plural = u'Soustředění'
ordering = ['-rocnik__rocnik', '-datum_zacatku']
# Interní ID
id = models.AutoField(primary_key = True)
rocnik = models.ForeignKey(Rocnik, verbose_name=u'ročník', related_name='soustredeni')
datum_zacatku = models.DateField(u'datum začátku', blank=True, null=True,
help_text=u'První den soustředění')
datum_konce = models.DateField(u'datum konce', blank=True, null=True,
help_text=u'Poslední den soustředění')
verejne_db = models.BooleanField(u'soustředění zveřejněno', db_column='verejne', default=False)
misto = models.CharField(u'místo soustředění', max_length=256, blank=True, default='',
help_text=u'Místo (název obce, volitelně též objektu')
ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci soustředění',
help_text=u'Seznam účastníků soustředění', through='Soustredeni_Ucastnici')
organizatori = models.ManyToManyField(Organizator,
verbose_name=u'Organizátoři soustředění',
help_text=u'Seznam organizátorů soustředění',
through='Soustredeni_Organizatori')
text = models.TextField(u'text k soustředění (HTML)', blank=True, default='')
TYP_JARNI = 'jarni'
TYP_PODZIMNI = 'podzimni'
TYP_VIKEND = 'vikend'
TYP_CHOICES = [
(TYP_JARNI, u'Jarní soustředění'),
(TYP_PODZIMNI, u'Podzimní soustředění'),
(TYP_VIKEND, u'Víkendový sraz'),
]
typ = models.CharField(u'typ akce', max_length=16, choices=TYP_CHOICES, blank=False, default=TYP_PODZIMNI)
exportovat = models.BooleanField(u'export do AESOPa', db_column='exportovat', default=False,
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))
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)
@python_2_unicode_compatible
class Soustredeni_Ucastnici(models.Model):
class Meta:
db_table = 'seminar_soustredeni_ucastnici'
verbose_name = u'Účast na soustředění'
verbose_name_plural = u'Účasti na soustředění'
ordering = ['soustredeni', 'resitel']
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel')
soustredeni = models.ForeignKey(Soustredeni, verbose_name=u'soustředění')
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
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, ))
# NOTE: Poteciální DB HOG bez select_related
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Soustredeni_Organizatori(models.Model):
class Meta:
db_table = 'seminar_soustredeni_organizatori'
verbose_name = u'Účast organizátorů na soustředění'
verbose_name_plural = u'Účasti organizátorů na soustředění'
ordering = ['soustredeni', 'organizator']
# Interní ID
id = models.AutoField(primary_key = True)
organizator = models.ForeignKey(Organizator, verbose_name=u'organizátor')
soustredeni = models.ForeignKey(Soustredeni, verbose_name=u'soustředění')
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
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, ))
# NOTE: Poteciální DB HOG bez select_related
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Konfera(models.Model):
class Meta:
db_table = 'seminar_konfera'
verbose_name = u'Konfera'
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')
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,
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)
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)
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',
upload_to = generate_filename_konfera, blank=True)
def __str__(self):
return force_unicode(u"%s: (%s)" % (self.nazev, self.soustredeni))
@reversion.register(ignore_duplicates=True)
@python_2_unicode_compatible
class Konfery_Ucastnici(models.Model):
class Meta:
db_table = 'seminar_konfery_ucastnici'
verbose_name = u'Účast na konfeře'
verbose_name_plural = u'Účasti na konfeře'
ordering = ['konfera', 'resitel']
# Interní ID
id = models.AutoField(primary_key = True)
resitel = models.ForeignKey(Resitel, verbose_name=u'řešitel')
konfera = models.ForeignKey(Konfera, verbose_name=u'konfera')
poznamka = models.TextField(u'neveřejná poznámka', blank=True,
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, ))
# NOTE: Poteciální DB HOG bez select_related
@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 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)
class VysledkyZaCislo(VysledkyBase):
class Meta:
db_table = 'seminar_body_za_cislo'
abstract = False
managed = False
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)')
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)')
@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)
@python_2_unicode_compatible
class Nastaveni(SingletonModel):
class Meta:
db_table = 'seminar_nastaveni'
verbose_name = u'Nastavení semináře'
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)
def __str__(self):
return u'Nastavení semináře'
def admin_url(self):
return reverse('admin:seminar_nastaveni_change', args=(self.id, ))
def verejne(self):
return False
@reversion.register(ignore_duplicates=True)
@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')
zverejneno = models.BooleanField('Zveřejněno', default="False")
def __str__(self):
return '[' + str(self.datum) + '] ' + self.text[0:50]
class Meta:
verbose_name = 'Novinka'
verbose_name_plural = 'Novinky'