Odstrel Modelu Odevzdavatko #64
20 changed files with 550 additions and 251 deletions
99
odevzdavatko/migrations/0001_create.py
Normal file
99
odevzdavatko/migrations/0001_create.py
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-22 22:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.utils.timezone
|
||||||
|
import odevzdavatko.models
|
||||||
|
|
||||||
|
def nastav_nove_contenttypes(apps, schema_editor):
|
||||||
|
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||||
|
for m in ('reseni', 'hodnoceni', 'reseni_resitele', 'prilohareseni'):
|
||||||
|
ContentType.objects.filter(app_label='seminar', model=m).update(app_label='odevzdavatko')
|
||||||
|
|
||||||
|
def nastav_stare_contenttypes(apps, schema_editor):
|
||||||
|
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||||
|
for m in ('reseni', 'hodnoceni', 'reseni_resitele', 'prilohareseni'):
|
||||||
|
ContentType.objects.filter(app_label='odevzdavatko', model=m).update(app_label='seminar')
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('seminar', '0132_unmanage_odevzdavatko'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Hodnoceni',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('body', models.DecimalField(blank=True, decimal_places=1, max_digits=8, null=True, verbose_name='body')),
|
||||||
|
('feedback', models.TextField(blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)', verbose_name='zpětná vazba')),
|
||||||
|
('cislo_body', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='hodnoceni', to='seminar.cislo', verbose_name='číslo pro body')),
|
||||||
|
('deadline_body', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='hodnoceni', to='seminar.deadline', verbose_name='deadline pro body')),
|
||||||
|
('problem', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='hodnoceni', to='seminar.problem', verbose_name='problém')),
|
||||||
|
('reseni', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='odevzdavatko.reseni', verbose_name='řešení')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Hodnocení',
|
||||||
|
'verbose_name_plural': 'Hodnocení',
|
||||||
|
'db_table': 'seminar_hodnoceni',
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PrilohaReseni',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('vytvoreno', models.DateTimeField(blank=True, default=django.utils.timezone.now, editable=False, verbose_name='vytvořeno')),
|
||||||
|
('soubor', models.FileField(upload_to=odevzdavatko.models.generate_filename, verbose_name='soubor')),
|
||||||
|
('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k příloze řešení (plain text), např. o původu', verbose_name='neveřejná poznámka')),
|
||||||
|
('res_poznamka', models.TextField(blank=True, help_text='Poznámka k příloze řešení, např. co daný soubor obsahuje', verbose_name='poznámka řešitele')),
|
||||||
|
('reseni', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='prilohy', to='odevzdavatko.reseni', verbose_name='řešení')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Příloha řešení',
|
||||||
|
'verbose_name_plural': 'Přílohy řešení',
|
||||||
|
'db_table': 'seminar_priloha_reseni',
|
||||||
|
'ordering': ['reseni', 'vytvoreno'],
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Reseni',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('cas_doruceni', models.DateTimeField(blank=True, default=django.utils.timezone.now, verbose_name='čas_doručení')),
|
||||||
|
('forma', models.CharField(choices=[('papir', 'Papírové řešení'), ('email', 'Emailem'), ('upload', 'Upload přes web')], default='email', max_length=16, verbose_name='forma řešení')),
|
||||||
|
('poznamka', models.TextField(blank=True, help_text='Neveřejná poznámka k řešení (plain text)', verbose_name='neveřejná poznámka')),
|
||||||
|
('zverejneno', models.BooleanField(default=False, help_text='Udává, zda je řešení zveřejněno', verbose_name='řešení zveřejněno')),
|
||||||
|
('problem', models.ManyToManyField(help_text='Problém', through='odevzdavatko.Hodnoceni', to='seminar.problem', verbose_name='problém')),
|
||||||
|
('resitele', models.ManyToManyField(help_text='Seznam autorů řešení', through='odevzdavatko.Reseni_Resitele', to='personalni.resitel', verbose_name='autoři řešení')),
|
||||||
|
('text_cely', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='reseni_cely_set', to='seminar.reseninode', verbose_name='Plná verze textu řešení')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Řešení',
|
||||||
|
'verbose_name_plural': 'Řešení',
|
||||||
|
'db_table': 'seminar_reseni',
|
||||||
|
'ordering': ['-cas_doruceni'],
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Reseni_Resitele',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('reseni', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='odevzdavatko.reseni', verbose_name='řešení')),
|
||||||
|
('resitele', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='personalni.resitel', verbose_name='řešitel')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Řešení řešitelů',
|
||||||
|
'verbose_name_plural': 'Řešení řešitelů',
|
||||||
|
'db_table': 'seminar_reseni_resitele',
|
||||||
|
'ordering': ['reseni', 'resitele'],
|
||||||
|
'managed': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.RunPython(nastav_nove_contenttypes, nastav_stare_contenttypes),
|
||||||
|
|
||||||
|
]
|
30
odevzdavatko/migrations/0002_manage.py
Normal file
30
odevzdavatko/migrations/0002_manage.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-23 21:07
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('odevzdavatko', '0001_create'),
|
||||||
|
('seminar', '0134_delete_odevzdavatko'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='hodnoceni',
|
||||||
|
options={'verbose_name': 'Hodnocení', 'verbose_name_plural': 'Hodnocení'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='prilohareseni',
|
||||||
|
options={'ordering': ['reseni', 'vytvoreno'], 'verbose_name': 'Příloha řešení', 'verbose_name_plural': 'Přílohy řešení'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='reseni',
|
||||||
|
options={'ordering': ['-cas_doruceni'], 'verbose_name': 'Řešení', 'verbose_name_plural': 'Řešení'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='reseni_resitele',
|
||||||
|
options={'ordering': ['reseni', 'resitele'], 'verbose_name': 'Řešení řešitelů', 'verbose_name_plural': 'Řešení řešitelů'},
|
||||||
|
),
|
||||||
|
]
|
13
odevzdavatko/migrations/0003_odstrel_odevzdavatka_post.py
Normal file
13
odevzdavatko/migrations/0003_odstrel_odevzdavatka_post.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-23 21:10
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('odevzdavatko', '0002_manage'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
239
odevzdavatko/models.py
Normal file
239
odevzdavatko/models.py
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
import reversion
|
||||||
|
|
||||||
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models import Sum
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
import seminar.models as am # tvorba
|
||||||
|
from seminar.models import base as bm
|
||||||
|
|
||||||
|
from odevzdavatko.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet
|
||||||
|
from personalni.models import Resitel
|
||||||
|
|
||||||
|
@reversion.register(ignore_duplicates=True)
|
||||||
|
class Reseni(bm.SeminarModelBase):
|
||||||
|
|
||||||
|
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']
|
||||||
|
|
||||||
|
# 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(am.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)
|
||||||
|
|
||||||
|
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'),
|
||||||
|
]
|
||||||
|
forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False,
|
||||||
|
default=FORMA_EMAIL)
|
||||||
|
|
||||||
|
text_cely = models.OneToOneField('seminar.ReseniNode', verbose_name='Plná verze textu řešení',
|
||||||
|
blank=True, null=True, related_name="reseni_cely_set",
|
||||||
|
on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
|
def verejne_url(self):
|
||||||
|
return str(reverse_lazy('odevzdavatko_detail_reseni', args=[self.id]))
|
||||||
|
|
||||||
|
def absolute_url(self):
|
||||||
|
return "https://" + str(get_current_site(None)) + self.verejne_url()
|
||||||
|
|
||||||
|
# má OneToOneField s:
|
||||||
|
# Konfera
|
||||||
|
|
||||||
|
# má ForeignKey s:
|
||||||
|
# Hodnoceni
|
||||||
|
|
||||||
|
def sum_body(self):
|
||||||
|
return self.hodnoceni_set.all().aggregate(Sum('body'))["body__sum"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}({}): {}({})".format(self.resitele.first(),len(self.resitele.all()), self.problem.first() ,len(self.problem.all()))
|
||||||
|
# NOTE: Potenciální DB HOG (bez select_related)
|
||||||
|
|
||||||
|
def deadline_reseni(self):
|
||||||
|
return am.Deadline.objects.filter(deadline__gte=self.cas_doruceni).order_by("deadline").first()
|
||||||
|
|
||||||
|
## 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(bm.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=True, null=True)
|
||||||
|
|
||||||
|
cislo_body = models.ForeignKey(am.Cislo, verbose_name='číslo pro body',
|
||||||
|
related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
# V ročníku < 26 nastaveno na deadline vygenerovaný pro původní cislo_body
|
||||||
|
deadline_body = models.ForeignKey(am.Deadline, verbose_name='deadline pro body',
|
||||||
|
related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
reseni = models.ForeignKey(Reseni, verbose_name='řešení', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
problem = models.ForeignKey(am.Problem, verbose_name='problém',
|
||||||
|
related_name='hodnoceni', on_delete=models.PROTECT)
|
||||||
|
|
||||||
|
feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_celkem(self):
|
||||||
|
# FIXME řeším jen prvního řešitele.
|
||||||
|
return Hodnoceni.objects.filter(problem=self.problem, reseni__resitele=self.reseni.resitele.first(), body__isnull=False).aggregate(Sum("body"))["body__sum"]
|
||||||
|
|
||||||
|
@body_celkem.setter
|
||||||
|
def body_celkem(self, value):
|
||||||
|
if value is None:
|
||||||
|
self.body = None
|
||||||
|
else:
|
||||||
|
if self.body is None:
|
||||||
|
self.body = 0
|
||||||
|
if self.body_celkem is None:
|
||||||
|
self.body += value
|
||||||
|
else:
|
||||||
|
self.body += value - self.body_celkem
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_neprepocitane(self):
|
||||||
|
if self.body is None:
|
||||||
|
return None
|
||||||
|
return inverze_vzorecku_na_prepocet(self.body, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@body_neprepocitane.setter
|
||||||
|
def body_neprepocitane(self, value):
|
||||||
|
if value is None:
|
||||||
|
self.body = None
|
||||||
|
else:
|
||||||
|
self.body = vzorecek_na_prepocet(value, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_neprepocitane_celkem(self):
|
||||||
|
if self.body_celkem is None:
|
||||||
|
return None
|
||||||
|
return inverze_vzorecku_na_prepocet(self.body_celkem, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@body_neprepocitane_celkem.setter
|
||||||
|
def body_neprepocitane_celkem(self, value):
|
||||||
|
if value is None:
|
||||||
|
self.body = None
|
||||||
|
else:
|
||||||
|
self.body_celkem = vzorecek_na_prepocet(value, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_max(self):
|
||||||
|
if self.body_neprepocitane_max is None:
|
||||||
|
return None
|
||||||
|
return vzorecek_na_prepocet(self.body_neprepocitane_max, self.reseni.resitele.count())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def body_neprepocitane_max(self):
|
||||||
|
if not isinstance(self.problem.get_real_instance(), am.Uloha):
|
||||||
|
return None
|
||||||
|
return self.problem.uloha.max_body
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}, {}, {}".format(self.problem, self.reseni, self.body)
|
||||||
|
|
||||||
|
def generate_filename(self, filename):
|
||||||
|
return os.path.join(
|
||||||
|
settings.SEMINAR_RESENI_DIR,
|
||||||
|
am.aux_generate_filename(self, filename)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@reversion.register(ignore_duplicates=True)
|
||||||
|
class PrilohaReseni(bm.SeminarModelBase):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'seminar_priloha_reseni'
|
||||||
|
verbose_name = 'Příloha řešení'
|
||||||
|
verbose_name_plural = 'Přílohy řešení'
|
||||||
|
ordering = ['reseni', 'vytvoreno']
|
||||||
|
|
||||||
|
# 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')
|
||||||
|
|
||||||
|
res_poznamka = models.TextField('poznámka řešitele', blank=True,
|
||||||
|
help_text='Poznámka k příloze řešení, např. co daný soubor obsahuje')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.soubor)
|
||||||
|
|
||||||
|
def split(self):
|
||||||
|
"Vrátí cestu rozsekanou po složkách. To se hodí v templatech"
|
||||||
|
# Věřím, že tohle funguje, případně použít os.path nebo pathlib.
|
||||||
|
return self.soubor.url.split('/')
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
|
@ -1,7 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from seminar.models.odevzdavatko import Reseni, Hodnoceni
|
from odevzdavatko.models import Reseni, Hodnoceni
|
||||||
|
|
||||||
|
|
||||||
def gen_reseni_ulohy(rnd, cisla, uloha, pocet_resitelu, poradi_cisla, resitele_cisla, resitele):
|
def gen_reseni_ulohy(rnd, cisla, uloha, pocet_resitelu, poradi_cisla, resitele_cisla, resitele):
|
||||||
|
|
13
personalni/migrations/0012_odstrel_odevzdavatka_pre.py
Normal file
13
personalni/migrations/0012_odstrel_odevzdavatka_pre.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-22 22:17
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalni', '0011_osloveni_vsechny_choices'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
14
personalni/migrations/0013_odstrel_odevzdavatka_post.py
Normal file
14
personalni/migrations/0013_odstrel_odevzdavatka_post.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-23 21:10
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('personalni', '0012_odstrel_odevzdavatka_pre'),
|
||||||
|
('odevzdavatko', '0003_odstrel_odevzdavatka_post'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
|
@ -296,7 +296,7 @@ class Resitel(SeminarModelBase):
|
||||||
def vsechny_body(self):
|
def vsechny_body(self):
|
||||||
"Spočítá body odjakživa."
|
"Spočítá body odjakživa."
|
||||||
vsechna_reseni = self.reseni_set.all()
|
vsechna_reseni = self.reseni_set.all()
|
||||||
from seminar.models.odevzdavatko import Hodnoceni
|
from odevzdavatko.models import Hodnoceni
|
||||||
vsechna_hodnoceni = Hodnoceni.objects.filter(
|
vsechna_hodnoceni = Hodnoceni.objects.filter(
|
||||||
reseni__in=vsechna_reseni)
|
reseni__in=vsechna_reseni)
|
||||||
return sum(h.body for h in list(vsechna_hodnoceni) if h.body is not None)
|
return sum(h.body for h in list(vsechna_hodnoceni) if h.body is not None)
|
||||||
|
@ -343,7 +343,7 @@ class Resitel(SeminarModelBase):
|
||||||
# - body z 25. ročníku a dříve byly shledány dvakrát hodnotnějšími
|
# - body z 25. ročníku a dříve byly shledány dvakrát hodnotnějšími
|
||||||
# - proto se započítávají dvojnásobně a byly posunuté hranice titulů
|
# - proto se započítávají dvojnásobně a byly posunuté hranice titulů
|
||||||
# - staré tituly se ale nemají odebrat, pokud řešitel v t.č. minulém (26.) ročníku měl titul, má ho mít pořád.
|
# - staré tituly se ale nemají odebrat, pokud řešitel v t.č. minulém (26.) ročníku měl titul, má ho mít pořád.
|
||||||
from seminar.models.odevzdavatko import Hodnoceni
|
from odevzdavatko.models import Hodnoceni
|
||||||
hodnoceni_do_25_rocniku = Hodnoceni.objects.filter(deadline_body__cislo__rocnik__rocnik__lte=25,reseni__in=self.reseni_set.all())
|
hodnoceni_do_25_rocniku = Hodnoceni.objects.filter(deadline_body__cislo__rocnik__rocnik__lte=25,reseni__in=self.reseni_set.all())
|
||||||
novejsi_hodnoceni = Hodnoceni.objects.filter(reseni__in=self.reseni_set.all()).difference(hodnoceni_do_25_rocniku)
|
novejsi_hodnoceni = Hodnoceni.objects.filter(reseni__in=self.reseni_set.all()).difference(hodnoceni_do_25_rocniku)
|
||||||
|
|
||||||
|
@ -381,7 +381,7 @@ class Resitel(SeminarModelBase):
|
||||||
else:
|
else:
|
||||||
return Titul.akad
|
return Titul.akad
|
||||||
|
|
||||||
from seminar.models.odevzdavatko import Hodnoceni
|
from odevzdavatko.models import Hodnoceni
|
||||||
hodnoceni_do_26_rocniku = Hodnoceni.objects.filter(deadline_body__cislo__rocnik__rocnik__lte=26,reseni__in=self.reseni_set.all())
|
hodnoceni_do_26_rocniku = Hodnoceni.objects.filter(deadline_body__cislo__rocnik__rocnik__lte=26,reseni__in=self.reseni_set.all())
|
||||||
novejsi_body = body_z_hodnoceni(
|
novejsi_body = body_z_hodnoceni(
|
||||||
Hodnoceni.objects.filter(reseni__in=self.reseni_set.all())
|
Hodnoceni.objects.filter(reseni__in=self.reseni_set.all())
|
||||||
|
|
14
seminar/migrations/0131_odstrel_odevzdavatka_pre.py
Normal file
14
seminar/migrations/0131_odstrel_odevzdavatka_pre.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-22 22:17
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('seminar', '0130_clanek_strana'),
|
||||||
|
('personalni', '0012_odstrel_odevzdavatka_pre'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
29
seminar/migrations/0132_unmanage_odevzdavatko.py
Normal file
29
seminar/migrations/0132_unmanage_odevzdavatko.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-22 22:31
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('seminar', '0131_odstrel_odevzdavatka_pre'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='hodnoceni',
|
||||||
|
options={'managed': False, 'verbose_name': 'Hodnocení', 'verbose_name_plural': 'Hodnocení'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='prilohareseni',
|
||||||
|
options={'managed': False, 'ordering': ['reseni', 'vytvoreno'], 'verbose_name': 'Příloha řešení', 'verbose_name_plural': 'Přílohy řešení'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='reseni',
|
||||||
|
options={'managed': False, 'ordering': ['-cas_doruceni'], 'verbose_name': 'Řešení', 'verbose_name_plural': 'Řešení'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='reseni_resitele',
|
||||||
|
options={'managed': False, 'ordering': ['reseni', 'resitele'], 'verbose_name': 'Řešení řešitelů', 'verbose_name_plural': 'Řešení řešitelů'},
|
||||||
|
),
|
||||||
|
]
|
20
seminar/migrations/0133_relink_odevzdavatko.py
Normal file
20
seminar/migrations/0133_relink_odevzdavatko.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-23 19:53
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('odevzdavatko', '0001_create'),
|
||||||
|
('seminar', '0132_unmanage_odevzdavatko'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='reseninode',
|
||||||
|
name='reseni',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='odevzdavatko.reseni', verbose_name='reseni'),
|
||||||
|
),
|
||||||
|
]
|
50
seminar/migrations/0134_delete_odevzdavatko.py
Normal file
50
seminar/migrations/0134_delete_odevzdavatko.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-23 19:56
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('seminar', '0133_relink_odevzdavatko'),
|
||||||
|
('odevzdavatko', '0001_create'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='prilohareseni',
|
||||||
|
name='reseni',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='reseni',
|
||||||
|
name='problem',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='reseni',
|
||||||
|
name='resitele',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='reseni',
|
||||||
|
name='text_cely',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='reseni_resitele',
|
||||||
|
name='reseni',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='reseni_resitele',
|
||||||
|
name='resitele',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Hodnoceni',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='PrilohaReseni',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Reseni',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Reseni_Resitele',
|
||||||
|
),
|
||||||
|
]
|
14
seminar/migrations/0135_odstrel_odevzdavatka_post.py
Normal file
14
seminar/migrations/0135_odstrel_odevzdavatka_post.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Django 4.2.13 on 2024-10-23 21:10
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('seminar', '0134_delete_odevzdavatko'),
|
||||||
|
('odevzdavatko', '0003_odstrel_odevzdavatka_post'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
]
|
|
@ -8,6 +8,9 @@ from various.models import Nastaveni
|
||||||
from personalni.models import Organizator, Resitel, Skola, Prijemce, Osoba
|
from personalni.models import Organizator, Resitel, Skola, Prijemce, Osoba
|
||||||
from soustredeni.models import Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Konfera, Konfery_Ucastnici
|
from soustredeni.models import Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Konfera, Konfery_Ucastnici
|
||||||
from novinky.models import Novinky
|
from novinky.models import Novinky
|
||||||
|
from odevzdavatko.models import Reseni, PrilohaReseni, Reseni_Resitele, Hodnoceni
|
||||||
|
|
||||||
# Kvůli migr. 0041
|
# Kvůli migr. 0041
|
||||||
from soustredeni.models import generate_filename_konfera
|
from soustredeni.models import generate_filename_konfera
|
||||||
|
# migr. 0001
|
||||||
|
from odevzdavatko.models import generate_filename
|
||||||
|
|
|
@ -14,8 +14,9 @@ class SeminarModelBase(models.Model):
|
||||||
# return "https://" + str(get_current_site(None)) + self.verejne_url()
|
# return "https://" + str(get_current_site(None)) + self.verejne_url()
|
||||||
|
|
||||||
def admin_url(self):
|
def admin_url(self):
|
||||||
model_name = self.__class__.__name__.lower()
|
app_name = self._meta.app_label
|
||||||
return reverse('admin:seminar_{}_change'.format(model_name), args=(self.id, ))
|
model_name = self._meta.model_name
|
||||||
|
return reverse('admin:{}_{}_change'.format(app_name, model_name), args=(self.id, ))
|
||||||
|
|
||||||
# def verejne_url(self):
|
# def verejne_url(self):
|
||||||
# return None
|
# return None
|
||||||
|
|
|
@ -1,244 +1,7 @@
|
||||||
import os
|
|
||||||
|
|
||||||
import reversion
|
|
||||||
|
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Sum
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from seminar.models import tvorba as am
|
|
||||||
from seminar.models import treenode as tm
|
from seminar.models import treenode as tm
|
||||||
from seminar.models import base as bm
|
from odevzdavatko.models import Reseni
|
||||||
|
|
||||||
from odevzdavatko.utils import vzorecek_na_prepocet, inverze_vzorecku_na_prepocet
|
|
||||||
from personalni.models import Resitel
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(ignore_duplicates=True)
|
|
||||||
class Reseni(bm.SeminarModelBase):
|
|
||||||
|
|
||||||
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']
|
|
||||||
|
|
||||||
# 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(am.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)
|
|
||||||
|
|
||||||
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'),
|
|
||||||
]
|
|
||||||
forma = models.CharField('forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False,
|
|
||||||
default=FORMA_EMAIL)
|
|
||||||
|
|
||||||
text_cely = models.OneToOneField('ReseniNode', verbose_name='Plná verze textu řešení',
|
|
||||||
blank=True, null=True, related_name="reseni_cely_set",
|
|
||||||
on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
def verejne_url(self):
|
|
||||||
return str(reverse_lazy('odevzdavatko_detail_reseni', args=[self.id]))
|
|
||||||
|
|
||||||
def absolute_url(self):
|
|
||||||
return "https://" + str(get_current_site(None)) + self.verejne_url()
|
|
||||||
|
|
||||||
# má OneToOneField s:
|
|
||||||
# Konfera
|
|
||||||
|
|
||||||
# má ForeignKey s:
|
|
||||||
# Hodnoceni
|
|
||||||
|
|
||||||
def sum_body(self):
|
|
||||||
return self.hodnoceni_set.all().aggregate(Sum('body'))["body__sum"]
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "{}({}): {}({})".format(self.resitele.first(),len(self.resitele.all()), self.problem.first() ,len(self.problem.all()))
|
|
||||||
# NOTE: Potenciální DB HOG (bez select_related)
|
|
||||||
|
|
||||||
def deadline_reseni(self):
|
|
||||||
return am.Deadline.objects.filter(deadline__gte=self.cas_doruceni).order_by("deadline").first()
|
|
||||||
|
|
||||||
## 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(bm.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=True, null=True)
|
|
||||||
|
|
||||||
cislo_body = models.ForeignKey(am.Cislo, verbose_name='číslo pro body',
|
|
||||||
related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
# V ročníku < 26 nastaveno na deadline vygenerovaný pro původní cislo_body
|
|
||||||
deadline_body = models.ForeignKey(am.Deadline, verbose_name='deadline pro body',
|
|
||||||
related_name='hodnoceni', blank=True, null=True, on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
reseni = models.ForeignKey(Reseni, verbose_name='řešení', on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
problem = models.ForeignKey(am.Problem, verbose_name='problém',
|
|
||||||
related_name='hodnoceni', on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
feedback = models.TextField('zpětná vazba', blank=True, default='', help_text='Zpětná vazba řešiteli (plain text)')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def body_celkem(self):
|
|
||||||
# FIXME řeším jen prvního řešitele.
|
|
||||||
return Hodnoceni.objects.filter(problem=self.problem, reseni__resitele=self.reseni.resitele.first(), body__isnull=False).aggregate(Sum("body"))["body__sum"]
|
|
||||||
|
|
||||||
@body_celkem.setter
|
|
||||||
def body_celkem(self, value):
|
|
||||||
if value is None:
|
|
||||||
self.body = None
|
|
||||||
else:
|
|
||||||
if self.body is None:
|
|
||||||
self.body = 0
|
|
||||||
if self.body_celkem is None:
|
|
||||||
self.body += value
|
|
||||||
else:
|
|
||||||
self.body += value - self.body_celkem
|
|
||||||
|
|
||||||
@property
|
|
||||||
def body_neprepocitane(self):
|
|
||||||
if self.body is None:
|
|
||||||
return None
|
|
||||||
return inverze_vzorecku_na_prepocet(self.body, self.reseni.resitele.count())
|
|
||||||
|
|
||||||
@body_neprepocitane.setter
|
|
||||||
def body_neprepocitane(self, value):
|
|
||||||
if value is None:
|
|
||||||
self.body = None
|
|
||||||
else:
|
|
||||||
self.body = vzorecek_na_prepocet(value, self.reseni.resitele.count())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def body_neprepocitane_celkem(self):
|
|
||||||
if self.body_celkem is None:
|
|
||||||
return None
|
|
||||||
return inverze_vzorecku_na_prepocet(self.body_celkem, self.reseni.resitele.count())
|
|
||||||
|
|
||||||
@body_neprepocitane_celkem.setter
|
|
||||||
def body_neprepocitane_celkem(self, value):
|
|
||||||
if value is None:
|
|
||||||
self.body = None
|
|
||||||
else:
|
|
||||||
self.body_celkem = vzorecek_na_prepocet(value, self.reseni.resitele.count())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def body_max(self):
|
|
||||||
if self.body_neprepocitane_max is None:
|
|
||||||
return None
|
|
||||||
return vzorecek_na_prepocet(self.body_neprepocitane_max, self.reseni.resitele.count())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def body_neprepocitane_max(self):
|
|
||||||
if not isinstance(self.problem.get_real_instance(), am.Uloha):
|
|
||||||
return None
|
|
||||||
return self.problem.uloha.max_body
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "{}, {}, {}".format(self.problem, self.reseni, self.body)
|
|
||||||
|
|
||||||
def generate_filename(self, filename):
|
|
||||||
return os.path.join(
|
|
||||||
settings.SEMINAR_RESENI_DIR,
|
|
||||||
am.aux_generate_filename(self, filename)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(ignore_duplicates=True)
|
|
||||||
class PrilohaReseni(bm.SeminarModelBase):
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
db_table = 'seminar_priloha_reseni'
|
|
||||||
verbose_name = 'Příloha řešení'
|
|
||||||
verbose_name_plural = 'Přílohy řešení'
|
|
||||||
ordering = ['reseni', 'vytvoreno']
|
|
||||||
|
|
||||||
# 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')
|
|
||||||
|
|
||||||
res_poznamka = models.TextField('poznámka řešitele', blank=True,
|
|
||||||
help_text='Poznámka k příloze řešení, např. co daný soubor obsahuje')
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.soubor)
|
|
||||||
|
|
||||||
def split(self):
|
|
||||||
"Vrátí cestu rozsekanou po složkách. To se hodí v templatech"
|
|
||||||
# Věřím, že tohle funguje, případně použít os.path nebo pathlib.
|
|
||||||
return self.soubor.url.split('/')
|
|
||||||
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
class ReseniNode(tm.TreeNode):
|
class ReseniNode(tm.TreeNode):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.conf import settings
|
||||||
from personalni.models import Resitel, Organizator
|
from personalni.models import Resitel, Organizator
|
||||||
|
|
||||||
from seminar.models.base import SeminarModelBase
|
from seminar.models.base import SeminarModelBase
|
||||||
from seminar.models import tvorba as am
|
import seminar.models as am # tvorba
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -77,10 +77,6 @@ class Soustredeni(SeminarModelBase):
|
||||||
#return reverse('seminar_soustredeni', kwargs={'pk': self.id})
|
#return reverse('seminar_soustredeni', kwargs={'pk': self.id})
|
||||||
return reverse('seminar_seznam_soustredeni')
|
return reverse('seminar_seznam_soustredeni')
|
||||||
|
|
||||||
def admin_url(self):
|
|
||||||
model_name = self.__class__.__name__.lower()
|
|
||||||
return reverse('admin:soustredeni_{}_change'.format(model_name), args=(self.id, ))
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(ignore_duplicates=True)
|
@reversion.register(ignore_duplicates=True)
|
||||||
class Soustredeni_Ucastnici(SeminarModelBase):
|
class Soustredeni_Ucastnici(SeminarModelBase):
|
||||||
|
|
|
@ -6,7 +6,7 @@ from typing import Sequence
|
||||||
import lorem
|
import lorem
|
||||||
|
|
||||||
from .models import Soustredeni, Konfera
|
from .models import Soustredeni, Konfera
|
||||||
import seminar.models.tvorba as am
|
import seminar.models as am # tvorba
|
||||||
import personalni.models as pm
|
import personalni.models as pm
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -5,5 +5,6 @@ makemigrations
|
||||||
! Doplnit ForeignKeys (Vypadá to, že se dá vesměs zkopírovat předpis z models.py, jen místo prvního fieldu dát `to='app.model'. Dokonce asi funguje použít už novou aplikaci pro vazby v rámci aplikace.)
|
! Doplnit ForeignKeys (Vypadá to, že se dá vesměs zkopírovat předpis z models.py, jen místo prvního fieldu dát `to='app.model'. Dokonce asi funguje použít už novou aplikaci pro vazby v rámci aplikace.)
|
||||||
To samé s ManyToManyFieldy (through= musí taky být 'app.model')
|
To samé s ManyToManyFieldy (through= musí taky být 'app.model')
|
||||||
(Zdá se, že jde dobastlit tuhle migraci polozpětně – doplnit co chybělo až podle toho, co vygeneruje migrace po zamanagování nového modelu.)
|
(Zdá se, že jde dobastlit tuhle migraci polozpětně – doplnit co chybělo až podle toho, co vygeneruje migrace po zamanagování nového modelu.)
|
||||||
|
Alternativa: zagitovat si unmanaged model, upravit ho na `managed = True`, vyrobit migrace, vyrobit je ještě jednou (z nějakého důvodu) a vykrást ty. Pak `models.py` vrátit do unmanaged stavu a soubory s novými migracemi smazat bez náhrady (obdobné vzniknou znovu v případě potřeby).
|
||||||
doplnit závislost na unmanage
|
doplnit závislost na unmanage
|
||||||
migrate
|
migrate
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
import soustredeni.models
|
import soustredeni.models
|
||||||
|
|
||||||
from seminar.models.tvorba import Rocnik, ZmrazenaVysledkovka, Deadline, Uloha, Problem, Tema, Clanek, Cislo
|
from seminar.models import Rocnik, ZmrazenaVysledkovka, Deadline, Uloha, Problem, Tema, Clanek, Cislo # tvorba
|
||||||
|
|
||||||
admin.site.register(Rocnik)
|
admin.site.register(Rocnik)
|
||||||
admin.site.register(ZmrazenaVysledkovka)
|
admin.site.register(ZmrazenaVysledkovka)
|
||||||
|
|
Loading…
Reference in a new issue