Merge remote branch 'origin/master' into Petr
Conflicts: seminar/admin.py
This commit is contained in:
		
						commit
						0fa9bbe76e
					
				
					 13 changed files with 352 additions and 73 deletions
				
			
		|  | @ -49,9 +49,11 @@ AUTHENTICATION_BACKENDS = ( | |||
| ) | ||||
| 
 | ||||
| TEMPLATE_LOADERS = ( | ||||
|     ('django.template.loaders.cached.Loader', ( | ||||
|         'django.template.loaders.filesystem.Loader', | ||||
|         'django.template.loaders.app_directories.Loader', | ||||
|         'django.template.loaders.eggs.Loader' | ||||
|     )), | ||||
| ) | ||||
| 
 | ||||
| MIDDLEWARE_CLASSES = ( | ||||
|  | @ -95,17 +97,22 @@ INSTALLED_APPS = ( | |||
|     'solo', | ||||
|     'ckeditor', | ||||
|     'taggit', | ||||
|     'autocomplete_light', | ||||
| 
 | ||||
|     # MaMweb | ||||
|     'mamweb', | ||||
|     'seminar', | ||||
| 
 | ||||
|     # Prvni: | ||||
|     'autocomplete_light', | ||||
|     'admin_tools', | ||||
|     'admin_tools.theming', | ||||
|     'admin_tools.menu', | ||||
|     'admin_tools.dashboard', | ||||
|     # Admin upravy: | ||||
| 
 | ||||
| #    'material', | ||||
| #    'material.admin', | ||||
| #    'admin_tools', | ||||
| #    'admin_tools.theming', | ||||
| #    'admin_tools.menu', | ||||
| #    'admin_tools.dashboard', | ||||
|     'flat', | ||||
| 
 | ||||
|     'django.contrib.admin', | ||||
| ) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								mamweb/static/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mamweb/static/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 218 B | 
|  | @ -2,6 +2,7 @@ | |||
| {% load staticfiles %} | ||||
| 
 | ||||
| {% block extrahead %} | ||||
| <link rel="shortcut icon" href="{% static 'favicon.ico' %}" type="image/x-icon"> | ||||
| <script src="{% static 'js/jquery-1.11.1.js' %}"></script> | ||||
| {% include 'autocomplete_light/static.html' %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
|   <head> | ||||
|     <title>{% block title %}Seminář M&M{% endblock title %}</title> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <link rel="shortcut icon" href="{% static 'favicon.ico' %}" type="image/x-icon"> | ||||
|     {% render_block "css" %} | ||||
|     <link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet"> | ||||
|     <link href="{% static 'css/bootstrap.css' %}" rel="stylesheet"> | ||||
|  |  | |||
|  | @ -17,9 +17,10 @@ django-sekizai==0.8.1 | |||
| django-countries==3.2 | ||||
| django-solo==1.1.0 | ||||
| django-ckeditor==4.4.7 | ||||
| django-admin-tools==0.5.2 | ||||
| django-flat-theme==0.9.3 | ||||
| django-taggit==0.14.0 | ||||
| django-autocomplete-light==2.1.1 | ||||
| # django-admin-tools==0.5.2 | ||||
| 
 | ||||
| # debug tools/extensions | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										215
									
								
								seminar/admin.py
									
									
									
									
									
								
							
							
						
						
									
										215
									
								
								seminar/admin.py
									
									
									
									
									
								
							|  | @ -1,30 +1,114 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from django.contrib import admin | ||||
| from django import forms | ||||
| from django.forms import widgets | ||||
| import reversion | ||||
| from solo.admin import SingletonModelAdmin | ||||
| from ckeditor.widgets import CKEditorWidget | ||||
| from django.db.models import Count | ||||
| from django.db import models | ||||
| 
 | ||||
| from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni | ||||
| from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici | ||||
| import autocomplete_light | ||||
| ### Nastaveni | ||||
| 
 | ||||
| 
 | ||||
| ### Globální nastavení | ||||
| 
 | ||||
| admin.site.register(Nastaveni, SingletonModelAdmin) | ||||
| 
 | ||||
| ### Skola | ||||
| 
 | ||||
| class SkolaAdmin(reversion.VersionAdmin): | ||||
|     fieldsets = [ | ||||
|         (None,              {'fields': ['nazev', 'kratky_nazev', 'je_zs', 'je_ss']}), | ||||
|         (u'Interní ID',     {'fields': ['aesop_id', 'izo'], 'classes': ['collapse']}), | ||||
|         (u'Adresa',         {'fields': ['ulice', 'mesto', 'psc', 'stat']}), | ||||
|         ] | ||||
|     list_display = ['nazev', 'aesop_id', 'mesto', 'ulice', 'stat', 'je_zs', 'je_ss'] | ||||
|     list_filter = ['stat', 'je_zs', 'je_ss'] | ||||
|     search_fields = ['nazev', 'mesto', 'ulice'] | ||||
| ### INLINES | ||||
| 
 | ||||
| admin.site.register(Skola, SkolaAdmin) | ||||
| class ResitelInline(admin.TabularInline): | ||||
|     model = Resitel | ||||
|     fields = ['jmeno', 'prijmeni', 'skola', 'mesto', 'rok_maturity', ] | ||||
|     readonly_fields = ['jmeno', 'prijmeni', 'skola', 'mesto', 'rok_maturity', ] | ||||
|     extra = 0 | ||||
| 
 | ||||
|     def has_add_permission(self, req): return False | ||||
| 
 | ||||
| 
 | ||||
| class CisloInline(admin.TabularInline): | ||||
|     model = Cislo | ||||
|     fields = ['cislo', 'datum_vydani', 'datum_deadline', 'verejne_db', 'poznamka'] | ||||
|     readonly_fields = ['cislo'] | ||||
|     extra = 0 | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
|     def has_add_permission(self, req): return False | ||||
| 
 | ||||
| 
 | ||||
| class PrilohaReseniInline(admin.StackedInline): | ||||
|     model = PrilohaReseni | ||||
|     fields = ['timestamp', 'soubor', 'poznamka'] | ||||
|     readonly_fields = ['timestamp'] | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
|     extra = 0 | ||||
| 
 | ||||
| class ReseniKProblemuInline(admin.TabularInline): | ||||
|     form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['resitel'], fields=['resitel']) | ||||
|     model = Reseni | ||||
|     fields = ['resitel', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka'] | ||||
|     readonly_fields = ['timestamp'] | ||||
|     extra = 0 | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(ReseniKProblemuInline, self).get_queryset(request) | ||||
|         return qs.select_related('problem', 'cislo_body', 'resitel') | ||||
| 
 | ||||
|     # Potenciální DB HOG (cislo_body se dotazovalo na cisla pri kazdem zobrazeni jejich selectu ...) | ||||
|     def formfield_for_dbfield(self, db_field, **kwargs): | ||||
|         formfield = super(ReseniKProblemuInline, self).formfield_for_dbfield(db_field, **kwargs) | ||||
|         if db_field.name == 'cislo_body': | ||||
|             # dirty trick so queryset is evaluated and cached in .choices | ||||
|             formfield.choices = formfield.choices | ||||
|         return formfield | ||||
| 
 | ||||
| 
 | ||||
| class ReseniKResiteliInline(admin.TabularInline): | ||||
|     model = Reseni | ||||
|     fields = ['problem', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka'] | ||||
|     readonly_fields = ['timestamp', 'problem'] | ||||
|     extra = 0 | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
|     def has_add_permission(self, req): return False | ||||
| 
 | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(ReseniKResiteliInline, self).get_queryset(request) | ||||
|         return qs.select_related('problem', 'cislo_body', 'resitel') | ||||
| 
 | ||||
|     # Potenciální DB HOG (cislo_body se dotazovalo na cisla pri kazdem zobrazeni jejich selectu ...) | ||||
|     def formfield_for_dbfield(self, db_field, **kwargs): | ||||
|         formfield = super(ReseniKResiteliInline, self).formfield_for_dbfield(db_field, **kwargs) | ||||
|         if db_field.name == 'cislo_body': | ||||
|             # dirty trick so queryset is evaluated and cached in .choices | ||||
|             formfield.choices = formfield.choices | ||||
|         return formfield | ||||
| 
 | ||||
| 
 | ||||
| class Soustredeni_UcastniciInline(admin.TabularInline): | ||||
|     form = autocomplete_light.modelform_factory(Soustredeni_Ucastnici, autocomplete_fields=['resitel'], fields=['resitel']) | ||||
|     model = Soustredeni_Ucastnici | ||||
|     fields = ['resitel', 'poznamka', ] | ||||
|     extra = 0 | ||||
|     formfield_overrides = { | ||||
|         models.TextField: {'widget': forms.TextInput}, | ||||
|     } | ||||
| 
 | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(Soustredeni_UcastniciInline, self).get_queryset(request) | ||||
|         return qs.select_related('resitel', 'soustredeni') | ||||
| 
 | ||||
| ### Resitel | ||||
| 
 | ||||
|  | @ -37,33 +121,55 @@ class ResitelAdmin(reversion.VersionAdmin): | |||
|         (u'Osobní údaje',   {'fields': ['pohlavi_muz', 'datum_narozeni', 'email', 'telefon']}), | ||||
|         (u'Adresa',         {'fields': ['ulice', 'mesto', 'psc', 'stat']}), | ||||
|         ] | ||||
|     list_display = ['jmeno', 'prijmeni', 'user', 'pohlavi_muz', 'skola', 'rok_maturity'] | ||||
|     list_display = ['jmeno', 'prijmeni', 'user', 'pohlavi_muz', 'skola', 'rok_maturity', 'pocet_reseni'] | ||||
|     list_filter = ['pohlavi_muz', 'rok_maturity', 'zasilat'] | ||||
|     search_fields = ['jmeno', 'prijmeni', 'ulice', 'user', 'mesto', 'email'] | ||||
|     inlines = [ReseniKResiteliInline] | ||||
| 
 | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(ResitelAdmin, self).get_queryset(request) | ||||
|         return qs.select_related('skola', 'user').annotate(pocet_reseni=Count('reseni')) | ||||
| 
 | ||||
|     def pocet_reseni(self, obj): | ||||
|         return obj.pocet_reseni | ||||
| 
 | ||||
| 
 | ||||
| admin.site.register(Resitel, ResitelAdmin) | ||||
| 
 | ||||
| 
 | ||||
| ### Skola | ||||
| 
 | ||||
| class SkolaAdmin(reversion.VersionAdmin): | ||||
|     fieldsets = [ | ||||
|         (None,              {'fields': ['nazev', 'kratky_nazev', 'je_zs', 'je_ss']}), | ||||
|         (u'Interní ID',     {'fields': ['aesop_id', 'izo'], 'classes': ['collapse']}), | ||||
|         (u'Adresa',         {'fields': ['ulice', 'mesto', 'psc', 'stat']}), | ||||
|         (None,              {'fields': ['poznamka']}), | ||||
|         ] | ||||
|     list_display = ['nazev', 'aesop_id', 'mesto', 'ulice', 'stat', 'je_zs', 'je_ss'] | ||||
|     list_filter = ['stat', 'je_zs', 'je_ss'] | ||||
|     search_fields = ['nazev', 'mesto', 'ulice'] | ||||
|     inlines = [ResitelInline] | ||||
| 
 | ||||
| admin.site.register(Skola, SkolaAdmin) | ||||
| 
 | ||||
| 
 | ||||
| ### Cislo | ||||
| 
 | ||||
| class CisloAdmin(reversion.VersionAdmin): | ||||
|     fieldsets = [ | ||||
|         (None,              {'fields': ['cislo', 'rocnik', 'verejne_db']}), | ||||
|         (None,              {'fields': ['cislo', 'rocnik', 'verejne_db', 'poznamka']}), | ||||
|         (u'Data',           {'fields': ['datum_vydani', 'datum_deadline']}), | ||||
|         ] | ||||
|     list_display = ['kod', 'rocnik', 'cislo', 'datum_vydani', 'datum_deadline', 'verejne'] | ||||
|     list_filter = ['rocnik'] | ||||
|     view_on_site = Cislo.verejne_url | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(CisloAdmin, self).get_queryset(request) | ||||
|         return qs.select_related('rocnik') | ||||
| 
 | ||||
| admin.site.register(Cislo, CisloAdmin) | ||||
| 
 | ||||
| class CisloInline(admin.StackedInline): | ||||
|     model = Cislo | ||||
|     fields = ['cislo', 'datum_vydani', 'datum_deadline', 'verejne_db'] | ||||
|     readonly_fields = ['cislo'] | ||||
|     extra = 0 | ||||
| 
 | ||||
| 
 | ||||
| ### Rocnik | ||||
| 
 | ||||
| class RocnikAdmin(reversion.VersionAdmin): | ||||
|  | @ -78,55 +184,50 @@ admin.site.register(Rocnik, RocnikAdmin) | |||
| 
 | ||||
| 
 | ||||
| ### PrilohaReseni | ||||
| 
 | ||||
| class PrilohaReseniAdmin(reversion.VersionAdmin): | ||||
|     readonly_fields = ['timestamp', 'reseni'] | ||||
|     fieldsets = [ | ||||
|         (None,              {'fields': ['reseni', 'soubor', 'timestamp']}), | ||||
|         (u'Poznámky',       {'fields': ['poznamka']}), | ||||
|         ] | ||||
|     list_display = ['reseni', 'soubor', 'timestamp'] | ||||
|     list_filter = ['reseni', 'timestamp'] | ||||
|     search_fields = [] | ||||
| 
 | ||||
| admin.site.register(PrilohaReseni, PrilohaReseniAdmin) | ||||
| 
 | ||||
| class PrilohaReseniInline(admin.StackedInline): | ||||
|     model = PrilohaReseni | ||||
|     fields = ['timestamp', 'soubor', 'poznamka'] | ||||
|     readonly_fields = ['timestamp'] | ||||
|     extra = 1 | ||||
| # NOTE: Nemá pravděpodobně smysl používat | ||||
| # class PrilohaReseniAdmin(reversion.VersionAdmin): | ||||
| #     readonly_fields = ['timestamp', 'reseni'] | ||||
| #     fieldsets = [ | ||||
| #         (None,              {'fields': ['reseni', 'soubor', 'timestamp']}), | ||||
| #         (u'Poznámky',       {'fields': ['poznamka']}), | ||||
| #         ] | ||||
| #     list_display = ['reseni', 'soubor', 'timestamp'] | ||||
| #     list_filter = ['reseni', 'timestamp'] | ||||
| #     search_fields = [] | ||||
| #  | ||||
| # admin.site.register(PrilohaReseni, PrilohaReseniAdmin) | ||||
| 
 | ||||
| 
 | ||||
| ### Reseni | ||||
| 
 | ||||
| class ReseniAdmin(reversion.VersionAdmin): | ||||
|     form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['problem'], fields=['problem']) | ||||
|     form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['problem', 'resitel'], fields=['problem', 'resitel']) | ||||
|     fieldsets = [ | ||||
|         (None,              {'fields': ['problem', 'resitel', 'forma', 'body', 'cislo_body', 'timestamp']}), | ||||
|         (u'Poznámky',       {'fields': ['poznamka']}), | ||||
|         ] | ||||
|     readonly_fields = ['timestamp'] | ||||
|     list_display = ['problem', 'resitel', 'forma', 'body', 'timestamp'] | ||||
|     list_display = ['problem', 'resitel', 'forma', 'body', 'timestamp', 'cislo_body'] | ||||
|     list_filter = ['body', 'timestamp', 'forma'] | ||||
|     search_fields = [] | ||||
|     inlines = [PrilohaReseniInline] | ||||
| 
 | ||||
| admin.site.register(Reseni, ReseniAdmin) | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(ReseniAdmin, self).get_queryset(request) | ||||
|         return qs.select_related('resitel', 'problem', 'cislo_body') | ||||
| 
 | ||||
| class ReseniInline(admin.TabularInline): | ||||
|     model = Reseni | ||||
|     fields = ['resitel', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka'] | ||||
|     readonly_fields = ['poznamka', 'resitel', 'timestamp', 'cislo_body', 'resitel', 'forma'] | ||||
|     extra = 0 | ||||
| admin.site.register(Reseni, ReseniAdmin) | ||||
| 
 | ||||
| 
 | ||||
| ### Problem | ||||
| 
 | ||||
| from autocomplete_light.contrib.taggit_field import TaggitField, TaggitWidget | ||||
| 
 | ||||
| #TODO: Autocomplete autor/opravovatel | ||||
| class ProblemAdminForm(forms.ModelForm): | ||||
|     text_problemu = forms.CharField(widget=CKEditorWidget()) | ||||
|     text_problemu_org = forms.CharField(widget=CKEditorWidget()) | ||||
|     zamereni = TaggitField(widget=TaggitWidget('TagAutocomplete')) | ||||
|     class Meta: | ||||
|         model = Problem | ||||
|         exclude = [] | ||||
|  | @ -135,17 +236,24 @@ class ProblemAdmin(reversion.VersionAdmin): | |||
|     form = ProblemAdminForm | ||||
|     fieldsets = [ | ||||
|         (None,              {'fields': ['nazev', 'typ', 'stav', 'autor', 'zamereni', 'body', 'timestamp']}), | ||||
|         (u'Vydání',         {'fields': ['cislo_zadani', 'kod', 'cislo_reseni', 'opravovatel']}), | ||||
|         (u'Texty',          {'fields': ['text_problemu', 'text_problemu_org']}), | ||||
|         (u'Vydání',         {'fields': ['cislo_zadani', 'kod', 'cislo_reseni', 'opravovatel', 'text_problemu']}), | ||||
|         (None,              {'fields': ['text_problemu_org']}), | ||||
|         ] | ||||
|     readonly_fields = ['timestamp'] | ||||
|     list_display = ['nazev', 'typ', 'kod', 'stav', 'autor', 'opravovatel', 'verejne', 'cislo_zadani'] | ||||
|     list_display = ['nazev', 'typ', 'kod', 'stav', 'autor', 'opravovatel', 'verejne', 'cislo_zadani', 'pocet_reseni'] | ||||
|     list_select_related = True | ||||
|     list_filter = ['typ', 'stav', 'timestamp'] | ||||
|     search_fields = ['nazev', 'kod', 'text_problemu_org', 'text_problemu'] | ||||
|     inlines = [ReseniInline] | ||||
|     inlines = [ReseniKProblemuInline] | ||||
|     view_on_site = Problem.verejne_url | ||||
| 
 | ||||
|     def get_queryset(self, request): | ||||
|         qs = super(ProblemAdmin, self).get_queryset(request) | ||||
|         return qs.select_related('autor', 'opravovatel', 'cislo_zadani', 'cislo_reseni').annotate(pocet_reseni=Count('reseni')) | ||||
| 
 | ||||
|     def pocet_reseni(self, obj): | ||||
|         return obj.pocet_reseni | ||||
| 
 | ||||
| admin.site.register(Problem, ProblemAdmin) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -157,8 +265,9 @@ class SoustredeniAdmin(reversion.VersionAdmin): | |||
|         (u'Data',           {'fields': ['datum_zacatku', 'datum_konce']}), | ||||
|         ] | ||||
|     list_display = ['rocnik', 'misto', 'datum_zacatku', 'verejne'] | ||||
|     inlines = [Soustredeni_UcastniciInline] | ||||
|     list_filter = ['rocnik'] | ||||
|     view_on_site = Soustredeni.verejne_url | ||||
|     # TODO: UcastNaSoustredeni jako inline | ||||
| 
 | ||||
| admin.site.register(Soustredeni, SoustredeniAdmin) | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,10 @@ | |||
| import autocomplete_light | ||||
| 
 | ||||
| from models import Skola, Resitel, Problem | ||||
| from taggit.models import Tag | ||||
| 
 | ||||
| 
 | ||||
| autocomplete_light.register(Tag) | ||||
| 
 | ||||
| 
 | ||||
| class SkolaAutocomplete(autocomplete_light.AutocompleteModelBase): | ||||
|  |  | |||
							
								
								
									
										18
									
								
								seminar/migrations/0012_remove_soustredeni_ucastnici.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								seminar/migrations/0012_remove_soustredeni_ucastnici.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0011_alter_timestamp_def'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.RemoveField( | ||||
|             model_name='soustredeni', | ||||
|             name='ucastnici', | ||||
|         ), | ||||
|     ] | ||||
|  | @ -0,0 +1,36 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0012_remove_soustredeni_ucastnici'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='Soustredeni_Ucastnici', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(serialize=False, primary_key=True)), | ||||
|                 ('poznamka', models.CharField(default=b'', help_text='Neve\u0159ejn\xe1 pozn\xe1mka k \xfa\u010dasti (plain text)', max_length=64, verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True)), | ||||
|                 ('resitel', models.ForeignKey(verbose_name='\u0159e\u0161itel', to='seminar.Resitel')), | ||||
|                 ('soustredeni', models.ForeignKey(verbose_name='soust\u0159ed\u011bn\xed', to='seminar.Soustredeni')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'ordering': ['soustredeni', 'resitel'], | ||||
|                 'db_table': 'seminar_soustredeni_ucastnici', | ||||
|                 'verbose_name': '\xda\u010dast na soust\u0159ed\u011bn\xed', | ||||
|                 'verbose_name_plural': '\xda\u010dasti na soust\u0159ed\u011bn\xed', | ||||
|             }, | ||||
|             bases=(models.Model,), | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name='soustredeni', | ||||
|             name='ucastnici', | ||||
|             field=models.ManyToManyField(help_text='Seznam \xfa\u010dastn\xedk\u016f soust\u0159ed\u011bn\xed', to='seminar.Resitel', verbose_name='\xfa\u010dastn\xedci soust\u0159ed\u011bn\xed', through='seminar.Soustredeni_Ucastnici'), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										50
									
								
								seminar/migrations/0014_uprava_poznamek.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								seminar/migrations/0014_uprava_poznamek.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import models, migrations | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('seminar', '0013_soustredeni_ucastnici_through_model'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.AlterModelOptions( | ||||
|             name='problem', | ||||
|             options={'ordering': ['nazev'], 'verbose_name': 'Probl\xe9m', 'verbose_name_plural': 'Probl\xe9my'}, | ||||
|         ), | ||||
|         migrations.AlterModelOptions( | ||||
|             name='reseni', | ||||
|             options={'ordering': ['problem_id', 'resitel_id'], 'verbose_name': '\u0158e\u0161en\xed', 'verbose_name_plural': '\u0158e\u0161en\xed'}, | ||||
|         ), | ||||
|         migrations.AlterModelOptions( | ||||
|             name='skola', | ||||
|             options={'ordering': ['mesto', 'nazev'], 'verbose_name': '\u0160kola', 'verbose_name_plural': '\u0160koly'}, | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name='cislo', | ||||
|             name='poznamka', | ||||
|             field=models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka k \u010d\xedslu (plain text)', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='problem', | ||||
|             name='text_problemu_org', | ||||
|             field=models.TextField(verbose_name='neve\u0159ejn\xe9 zad\xe1n\xed a organiz\xe1torsk\xe9 a pozn\xe1mky', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='reseni', | ||||
|             name='poznamka', | ||||
|             field=models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka k \u0159e\u0161en\xed (plain text)', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|         migrations.AlterField( | ||||
|             model_name='soustredeni_ucastnici', | ||||
|             name='poznamka', | ||||
|             field=models.TextField(help_text='Neve\u0159ejn\xe1 pozn\xe1mka k \xfa\u010dasti (plain text)', verbose_name='neve\u0159ejn\xe1 pozn\xe1mka', blank=True), | ||||
|             preserve_default=True, | ||||
|         ), | ||||
|     ] | ||||
|  | @ -10,6 +10,8 @@ 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_countries.fields import CountryField | ||||
| from solo.models import SingletonModel | ||||
|  | @ -19,7 +21,6 @@ import reversion | |||
| 
 | ||||
| from seminar.utils import roman | ||||
| 
 | ||||
| # TODO společná báze (admin url, url, veřejné, ...) | ||||
| class SeminarModelBase(models.Model): | ||||
| 
 | ||||
|     class Meta: | ||||
|  | @ -54,6 +55,7 @@ class Skola(SeminarModelBase): | |||
|         db_table = 'seminar_skoly' | ||||
|         verbose_name = u'Škola' | ||||
|         verbose_name_plural = u'Školy' | ||||
|         ordering = ['mesto', 'nazev'] | ||||
| 
 | ||||
|     # Interní ID | ||||
|     id = models.AutoField(primary_key = True) | ||||
|  | @ -229,6 +231,16 @@ class Rocnik(SeminarModelBase): | |||
|     def verejne_url(self): | ||||
|         return reverse('seminar_rocnik', kwargs={'pk': self.id}) | ||||
| 
 | ||||
|     @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 | ||||
|          | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revisions=True) | ||||
| @python_2_unicode_compatible | ||||
|  | @ -256,12 +268,17 @@ class Cislo(SeminarModelBase): | |||
| 
 | ||||
|     verejne_db = models.BooleanField(u'číslo zveřejněno', db_column='verejne', default=False) | ||||
| 
 | ||||
|     poznamka = models.TextField(u'neveřejná poznámka', blank=True, | ||||
|         help_text=u'Neveřejná poznámka k číslu (plain text)') | ||||
| 
 | ||||
|     def kod(self): | ||||
|         return u'%s.%s' % (self.rocnik.rocnik, self.cislo) | ||||
|     kod.short_description = u'Kód čísla' | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return force_unicode(u'%s' % (self.kod(),)) | ||||
|         # Potenciální DB HOG, pokud by se ročník neckešoval | ||||
|         r = Rocnik.cached_rocnik(self.rocnik_id) | ||||
|         return force_unicode(u'%s.%s' % (r.rocnik, self.cislo, )) | ||||
| 
 | ||||
|     def verejne(self): | ||||
|         return self.verejne_db | ||||
|  | @ -294,6 +311,7 @@ class Problem(SeminarModelBase): | |||
|         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) | ||||
|  | @ -327,7 +345,7 @@ class Problem(SeminarModelBase): | |||
| 
 | ||||
|     zamereni = TaggableManager(verbose_name=u'zaměření', help_text='Zaměření M/F/I/O problému, příp. další tagy', blank=True) | ||||
| 
 | ||||
|     text_problemu_org = models.TextField(u'organizátorský (neveřejný) text', blank=True) | ||||
|     text_problemu_org = models.TextField(u'neveřejné zadání a organizátorské a poznámky', blank=True) | ||||
| 
 | ||||
|     text_problemu = models.TextField(u'veřejný text zadání a řešení', blank=True) | ||||
| 
 | ||||
|  | @ -354,7 +372,7 @@ class Problem(SeminarModelBase): | |||
|         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 (%s)' % (self.nazev, self.stav)) | ||||
|         return force_unicode(u'%s' % (self.nazev, )) | ||||
| 
 | ||||
|     def kod_v_rocniku(self): | ||||
|         if self.typ == self.TYP_ULOHA: | ||||
|  | @ -379,7 +397,7 @@ class Reseni(SeminarModelBase): | |||
|         db_table = 'seminar_reseni' | ||||
|         verbose_name = u'Řešení' | ||||
|         verbose_name_plural = u'Řešení' | ||||
|         ordering = ['problem', 'resitel'] | ||||
|         ordering = ['problem_id', 'resitel_id'] | ||||
| 
 | ||||
|     # Interní ID | ||||
|     id = models.AutoField(primary_key = True) | ||||
|  | @ -405,10 +423,11 @@ class Reseni(SeminarModelBase): | |||
|     forma = models.CharField(u'forma řešení', max_length=16, choices=FORMA_CHOICES, blank=False, default=FORMA_PAPIR) | ||||
| 
 | ||||
|     poznamka = models.TextField(u'neveřejná poznámka', blank=True, | ||||
|         help_text=u'Neveřejná poznámka k řešení (plain text, editace v detailu řešení)') | ||||
|         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) | ||||
| 
 | ||||
| 
 | ||||
| # PrilohaReseni method | ||||
|  | @ -418,7 +437,7 @@ def generate_filename(self, filename): | |||
|     fname = "%s_%s" % ( | ||||
|         timezone.now().strftime('%Y-%m-%d-%H:%M'), | ||||
|         clean) | ||||
|     return os.path.join(settings.SEMINAR_RESENI_DIRNAME, datedir, fname) | ||||
|     return os.path.join(settings.SEMINAR_RESENI_DIR, datedir, fname) | ||||
| 
 | ||||
| 
 | ||||
| @reversion.register(ignore_duplicate_revisions=True) | ||||
|  | @ -474,10 +493,10 @@ class Soustredeni(SeminarModelBase): | |||
|         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í', db_table='seminar_soustredeni_ucastnici') | ||||
|         help_text=u'Seznam účastníků soustředění', through='Soustredeni_Ucastnici') | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return force_unicode(u'%s (%s)' % (self.misto, self.datum_zacatek)) | ||||
|         return force_unicode(u'%s (%s)' % (self.misto, self.datum_zacatku)) | ||||
| 
 | ||||
|     def verejne(self): | ||||
|         return self.verejne_db | ||||
|  | @ -487,6 +506,30 @@ class Soustredeni(SeminarModelBase): | |||
|         return reverse('seminar_soustredeni', kwargs={'pk': self.id}) | ||||
| 
 | ||||
| 
 | ||||
| @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 | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class VysledkyBase(SeminarModelBase): | ||||
| 
 | ||||
|  | @ -507,6 +550,7 @@ class VysledkyBase(SeminarModelBase): | |||
| 
 | ||||
|     def __str__(self): | ||||
|         return force_unicode(u"%s: %sb (%s)" % (self.resitel.plne_jmeno(), self.body, str(self.cislo))) | ||||
|         # NOTE: DB HOG (ale nepouzivany) | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class VysledkyZaCislo(VysledkyBase): | ||||
|  | @ -517,6 +561,7 @@ class VysledkyZaCislo(VysledkyBase): | |||
|         managed = False | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         # NOTE: DB HOG (ale nepouzivany) | ||||
|         return force_unicode(u"%s: %sb (za %s)" % (self.resitel.plne_jmeno(), self.body, str(self.cislo))) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -531,6 +576,7 @@ class VysledkyKCislu(VysledkyBase): | |||
|     body_celkem = models.IntegerField(u'body celkem do čísla', db_column='body_celkem') | ||||
| 
 | ||||
|     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))) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ urlpatterns = patterns('', | |||
|     url(r'^rocnik/(?P<pk>\d+)/$', views.RocnikView.as_view(), name='seminar_rocnik'), | ||||
|     url(r'^cislo/(?P<pk>\d+)/$', views.CisloView.as_view(), name='seminar_cislo'), | ||||
|     url(r'^problem/(?P<pk>\d+)/$', views.ProblemView.as_view(), name='seminar_problem'), | ||||
|     url(r'^soustredeni/(?P<pk>\d+)/$', views.SoustredeniView.as_view(), name='seminar_soustredeni'), | ||||
| 
 | ||||
|     url(r'^zadani/$', views.AktualniZadaniView, name='seminar_aktualni_zadani'), | ||||
| 
 | ||||
|     url(r'^aesop-export/mam-rocnik-(?P<prvni_rok>\d+)\.csv$', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404, render | |||
| from django.http import HttpResponseRedirect | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.views import generic | ||||
| from .models import Problem, Cislo, Reseni, VysledkyKCislu, Nastaveni, Rocnik | ||||
| from .models import Problem, Cislo, Reseni, VysledkyKCislu, Nastaveni, Rocnik, Soustredeni | ||||
| 
 | ||||
| 
 | ||||
| def AktualniZadaniView(request): | ||||
|  | @ -16,6 +16,10 @@ class RocnikView(generic.DetailView): | |||
|     model = Rocnik | ||||
|     template_name = 'seminar/rocnik.html' | ||||
| 
 | ||||
| class SoustredeniView(generic.DetailView): | ||||
|     model = Soustredeni | ||||
|     template_name = 'seminar/soustredeni.html' | ||||
| 
 | ||||
| class ProblemView(generic.DetailView): | ||||
|     model = Problem | ||||
|     template_name = 'seminar/problem.html' | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Bc. Petr Pecha
						Bc. Petr Pecha