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 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): | ||||
|  |  | |||
							
								
								
									
										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): | ||||
| 		"Spočítá body odjakživa." | ||||
| 		vsechna_reseni = self.reseni_set.all() | ||||
| 		from seminar.models.odevzdavatko import Hodnoceni | ||||
| 		from odevzdavatko.models import Hodnoceni | ||||
| 		vsechna_hodnoceni = Hodnoceni.objects.filter( | ||||
| 			reseni__in=vsechna_reseni) | ||||
| 		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 | ||||
| 		#  - 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. | ||||
| 		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()) | ||||
| 		novejsi_hodnoceni = Hodnoceni.objects.filter(reseni__in=self.reseni_set.all()).difference(hodnoceni_do_25_rocniku) | ||||
| 
 | ||||
|  | @ -381,7 +381,7 @@ class Resitel(SeminarModelBase): | |||
| 			else: | ||||
| 				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()) | ||||
| 		novejsi_body = body_z_hodnoceni( | ||||
| 			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 soustredeni.models import Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Konfera, Konfery_Ucastnici | ||||
| from novinky.models import Novinky | ||||
| from odevzdavatko.models import Reseni, PrilohaReseni, Reseni_Resitele, Hodnoceni | ||||
| 
 | ||||
| # Kvůli migr. 0041 | ||||
| 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() | ||||
| 
 | ||||
| 	def admin_url(self): | ||||
| 		model_name = self.__class__.__name__.lower() | ||||
| 		return reverse('admin:seminar_{}_change'.format(model_name), args=(self.id, )) | ||||
| 		app_name = self._meta.app_label | ||||
| 		model_name = self._meta.model_name | ||||
| 		return reverse('admin:{}_{}_change'.format(app_name, model_name), args=(self.id, )) | ||||
| 
 | ||||
| # def verejne_url(self): | ||||
| # 	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.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 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('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 | ||||
| from odevzdavatko.models import Reseni | ||||
| 
 | ||||
| class ReseniNode(tm.TreeNode): | ||||
| 	class Meta: | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ from django.conf import settings | |||
| from personalni.models import Resitel, Organizator | ||||
| 
 | ||||
| from seminar.models.base import SeminarModelBase | ||||
| from seminar.models import tvorba as am | ||||
| import seminar.models as am # tvorba | ||||
| 
 | ||||
| logger = logging.getLogger(__name__) | ||||
| 
 | ||||
|  | @ -77,10 +77,6 @@ class Soustredeni(SeminarModelBase): | |||
| 		#return reverse('seminar_soustredeni', kwargs={'pk': self.id}) | ||||
| 		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) | ||||
| class Soustredeni_Ucastnici(SeminarModelBase): | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ from typing import Sequence | |||
| import lorem | ||||
| 
 | ||||
| from .models import Soustredeni, Konfera | ||||
| import seminar.models.tvorba as am | ||||
| import seminar.models as am # tvorba | ||||
| import personalni.models as pm | ||||
| 
 | ||||
| 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.) | ||||
| 	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.) | ||||
| 	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 | ||||
| migrate | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ from django.utils.safestring import mark_safe | |||
| 
 | ||||
| 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(ZmrazenaVysledkovka) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue