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 = (
|
TEMPLATE_LOADERS = (
|
||||||
'django.template.loaders.filesystem.Loader',
|
('django.template.loaders.cached.Loader', (
|
||||||
'django.template.loaders.app_directories.Loader',
|
'django.template.loaders.filesystem.Loader',
|
||||||
'django.template.loaders.eggs.Loader'
|
'django.template.loaders.app_directories.Loader',
|
||||||
|
'django.template.loaders.eggs.Loader'
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
|
@ -95,17 +97,22 @@ INSTALLED_APPS = (
|
||||||
'solo',
|
'solo',
|
||||||
'ckeditor',
|
'ckeditor',
|
||||||
'taggit',
|
'taggit',
|
||||||
|
'autocomplete_light',
|
||||||
|
|
||||||
# MaMweb
|
# MaMweb
|
||||||
'mamweb',
|
'mamweb',
|
||||||
'seminar',
|
'seminar',
|
||||||
|
|
||||||
# Prvni:
|
# Admin upravy:
|
||||||
'autocomplete_light',
|
|
||||||
'admin_tools',
|
# 'material',
|
||||||
'admin_tools.theming',
|
# 'material.admin',
|
||||||
'admin_tools.menu',
|
# 'admin_tools',
|
||||||
'admin_tools.dashboard',
|
# 'admin_tools.theming',
|
||||||
|
# 'admin_tools.menu',
|
||||||
|
# 'admin_tools.dashboard',
|
||||||
|
'flat',
|
||||||
|
|
||||||
'django.contrib.admin',
|
'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 %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block extrahead %}
|
{% block extrahead %}
|
||||||
|
<link rel="shortcut icon" href="{% static 'favicon.ico' %}" type="image/x-icon">
|
||||||
<script src="{% static 'js/jquery-1.11.1.js' %}"></script>
|
<script src="{% static 'js/jquery-1.11.1.js' %}"></script>
|
||||||
{% include 'autocomplete_light/static.html' %}
|
{% include 'autocomplete_light/static.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<head>
|
<head>
|
||||||
<title>{% block title %}Seminář M&M{% endblock title %}</title>
|
<title>{% block title %}Seminář M&M{% endblock title %}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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" %}
|
{% render_block "css" %}
|
||||||
<link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
|
<link href="{% static 'css/bootstrap-theme.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/bootstrap.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-countries==3.2
|
||||||
django-solo==1.1.0
|
django-solo==1.1.0
|
||||||
django-ckeditor==4.4.7
|
django-ckeditor==4.4.7
|
||||||
django-admin-tools==0.5.2
|
django-flat-theme==0.9.3
|
||||||
django-taggit==0.14.0
|
django-taggit==0.14.0
|
||||||
django-autocomplete-light==2.1.1
|
django-autocomplete-light==2.1.1
|
||||||
|
# django-admin-tools==0.5.2
|
||||||
|
|
||||||
# debug tools/extensions
|
# debug tools/extensions
|
||||||
|
|
||||||
|
|
215
seminar/admin.py
215
seminar/admin.py
|
@ -1,30 +1,114 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.forms import widgets
|
||||||
import reversion
|
import reversion
|
||||||
from solo.admin import SingletonModelAdmin
|
from solo.admin import SingletonModelAdmin
|
||||||
from ckeditor.widgets import CKEditorWidget
|
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
|
import autocomplete_light
|
||||||
### Nastaveni
|
|
||||||
|
|
||||||
|
### Globální nastavení
|
||||||
|
|
||||||
admin.site.register(Nastaveni, SingletonModelAdmin)
|
admin.site.register(Nastaveni, SingletonModelAdmin)
|
||||||
|
|
||||||
### Skola
|
|
||||||
|
|
||||||
class SkolaAdmin(reversion.VersionAdmin):
|
### INLINES
|
||||||
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']
|
|
||||||
|
|
||||||
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
|
### Resitel
|
||||||
|
|
||||||
|
@ -37,33 +121,55 @@ class ResitelAdmin(reversion.VersionAdmin):
|
||||||
(u'Osobní údaje', {'fields': ['pohlavi_muz', 'datum_narozeni', 'email', 'telefon']}),
|
(u'Osobní údaje', {'fields': ['pohlavi_muz', 'datum_narozeni', 'email', 'telefon']}),
|
||||||
(u'Adresa', {'fields': ['ulice', 'mesto', 'psc', 'stat']}),
|
(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']
|
list_filter = ['pohlavi_muz', 'rok_maturity', 'zasilat']
|
||||||
search_fields = ['jmeno', 'prijmeni', 'ulice', 'user', 'mesto', 'email']
|
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)
|
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
|
### Cislo
|
||||||
|
|
||||||
class CisloAdmin(reversion.VersionAdmin):
|
class CisloAdmin(reversion.VersionAdmin):
|
||||||
fieldsets = [
|
fieldsets = [
|
||||||
(None, {'fields': ['cislo', 'rocnik', 'verejne_db']}),
|
(None, {'fields': ['cislo', 'rocnik', 'verejne_db', 'poznamka']}),
|
||||||
(u'Data', {'fields': ['datum_vydani', 'datum_deadline']}),
|
(u'Data', {'fields': ['datum_vydani', 'datum_deadline']}),
|
||||||
]
|
]
|
||||||
list_display = ['kod', 'rocnik', 'cislo', 'datum_vydani', 'datum_deadline', 'verejne']
|
list_display = ['kod', 'rocnik', 'cislo', 'datum_vydani', 'datum_deadline', 'verejne']
|
||||||
list_filter = ['rocnik']
|
list_filter = ['rocnik']
|
||||||
view_on_site = Cislo.verejne_url
|
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)
|
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
|
### Rocnik
|
||||||
|
|
||||||
class RocnikAdmin(reversion.VersionAdmin):
|
class RocnikAdmin(reversion.VersionAdmin):
|
||||||
|
@ -78,55 +184,50 @@ admin.site.register(Rocnik, RocnikAdmin)
|
||||||
|
|
||||||
|
|
||||||
### PrilohaReseni
|
### PrilohaReseni
|
||||||
|
# NOTE: Nemá pravděpodobně smysl používat
|
||||||
class PrilohaReseniAdmin(reversion.VersionAdmin):
|
# class PrilohaReseniAdmin(reversion.VersionAdmin):
|
||||||
readonly_fields = ['timestamp', 'reseni']
|
# readonly_fields = ['timestamp', 'reseni']
|
||||||
fieldsets = [
|
# fieldsets = [
|
||||||
(None, {'fields': ['reseni', 'soubor', 'timestamp']}),
|
# (None, {'fields': ['reseni', 'soubor', 'timestamp']}),
|
||||||
(u'Poznámky', {'fields': ['poznamka']}),
|
# (u'Poznámky', {'fields': ['poznamka']}),
|
||||||
]
|
# ]
|
||||||
list_display = ['reseni', 'soubor', 'timestamp']
|
# list_display = ['reseni', 'soubor', 'timestamp']
|
||||||
list_filter = ['reseni', 'timestamp']
|
# list_filter = ['reseni', 'timestamp']
|
||||||
search_fields = []
|
# search_fields = []
|
||||||
|
#
|
||||||
admin.site.register(PrilohaReseni, PrilohaReseniAdmin)
|
# admin.site.register(PrilohaReseni, PrilohaReseniAdmin)
|
||||||
|
|
||||||
class PrilohaReseniInline(admin.StackedInline):
|
|
||||||
model = PrilohaReseni
|
|
||||||
fields = ['timestamp', 'soubor', 'poznamka']
|
|
||||||
readonly_fields = ['timestamp']
|
|
||||||
extra = 1
|
|
||||||
|
|
||||||
|
|
||||||
### Reseni
|
### Reseni
|
||||||
|
|
||||||
class ReseniAdmin(reversion.VersionAdmin):
|
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 = [
|
fieldsets = [
|
||||||
(None, {'fields': ['problem', 'resitel', 'forma', 'body', 'cislo_body', 'timestamp']}),
|
(None, {'fields': ['problem', 'resitel', 'forma', 'body', 'cislo_body', 'timestamp']}),
|
||||||
(u'Poznámky', {'fields': ['poznamka']}),
|
(u'Poznámky', {'fields': ['poznamka']}),
|
||||||
]
|
]
|
||||||
readonly_fields = ['timestamp']
|
readonly_fields = ['timestamp']
|
||||||
list_display = ['problem', 'resitel', 'forma', 'body', 'timestamp']
|
list_display = ['problem', 'resitel', 'forma', 'body', 'timestamp', 'cislo_body']
|
||||||
list_filter = ['body', 'timestamp', 'forma']
|
list_filter = ['body', 'timestamp', 'forma']
|
||||||
search_fields = []
|
search_fields = []
|
||||||
inlines = [PrilohaReseniInline]
|
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):
|
admin.site.register(Reseni, ReseniAdmin)
|
||||||
model = Reseni
|
|
||||||
fields = ['resitel', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka']
|
|
||||||
readonly_fields = ['poznamka', 'resitel', 'timestamp', 'cislo_body', 'resitel', 'forma']
|
|
||||||
extra = 0
|
|
||||||
|
|
||||||
|
|
||||||
### Problem
|
### Problem
|
||||||
|
|
||||||
|
from autocomplete_light.contrib.taggit_field import TaggitField, TaggitWidget
|
||||||
|
|
||||||
#TODO: Autocomplete autor/opravovatel
|
#TODO: Autocomplete autor/opravovatel
|
||||||
class ProblemAdminForm(forms.ModelForm):
|
class ProblemAdminForm(forms.ModelForm):
|
||||||
text_problemu = forms.CharField(widget=CKEditorWidget())
|
text_problemu = forms.CharField(widget=CKEditorWidget())
|
||||||
text_problemu_org = forms.CharField(widget=CKEditorWidget())
|
text_problemu_org = forms.CharField(widget=CKEditorWidget())
|
||||||
|
zamereni = TaggitField(widget=TaggitWidget('TagAutocomplete'))
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Problem
|
model = Problem
|
||||||
exclude = []
|
exclude = []
|
||||||
|
@ -135,17 +236,24 @@ class ProblemAdmin(reversion.VersionAdmin):
|
||||||
form = ProblemAdminForm
|
form = ProblemAdminForm
|
||||||
fieldsets = [
|
fieldsets = [
|
||||||
(None, {'fields': ['nazev', 'typ', 'stav', 'autor', 'zamereni', 'body', 'timestamp']}),
|
(None, {'fields': ['nazev', 'typ', 'stav', 'autor', 'zamereni', 'body', 'timestamp']}),
|
||||||
(u'Vydání', {'fields': ['cislo_zadani', 'kod', 'cislo_reseni', 'opravovatel']}),
|
(u'Vydání', {'fields': ['cislo_zadani', 'kod', 'cislo_reseni', 'opravovatel', 'text_problemu']}),
|
||||||
(u'Texty', {'fields': ['text_problemu', 'text_problemu_org']}),
|
(None, {'fields': ['text_problemu_org']}),
|
||||||
]
|
]
|
||||||
readonly_fields = ['timestamp']
|
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_select_related = True
|
||||||
list_filter = ['typ', 'stav', 'timestamp']
|
list_filter = ['typ', 'stav', 'timestamp']
|
||||||
search_fields = ['nazev', 'kod', 'text_problemu_org', 'text_problemu']
|
search_fields = ['nazev', 'kod', 'text_problemu_org', 'text_problemu']
|
||||||
inlines = [ReseniInline]
|
inlines = [ReseniKProblemuInline]
|
||||||
view_on_site = Problem.verejne_url
|
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)
|
admin.site.register(Problem, ProblemAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,8 +265,9 @@ class SoustredeniAdmin(reversion.VersionAdmin):
|
||||||
(u'Data', {'fields': ['datum_zacatku', 'datum_konce']}),
|
(u'Data', {'fields': ['datum_zacatku', 'datum_konce']}),
|
||||||
]
|
]
|
||||||
list_display = ['rocnik', 'misto', 'datum_zacatku', 'verejne']
|
list_display = ['rocnik', 'misto', 'datum_zacatku', 'verejne']
|
||||||
|
inlines = [Soustredeni_UcastniciInline]
|
||||||
list_filter = ['rocnik']
|
list_filter = ['rocnik']
|
||||||
view_on_site = Soustredeni.verejne_url
|
view_on_site = Soustredeni.verejne_url
|
||||||
# TODO: UcastNaSoustredeni jako inline
|
|
||||||
|
|
||||||
admin.site.register(Soustredeni, SoustredeniAdmin)
|
admin.site.register(Soustredeni, SoustredeniAdmin)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
import autocomplete_light
|
import autocomplete_light
|
||||||
|
|
||||||
from models import Skola, Resitel, Problem
|
from models import Skola, Resitel, Problem
|
||||||
|
from taggit.models import Tag
|
||||||
|
|
||||||
|
|
||||||
|
autocomplete_light.register(Tag)
|
||||||
|
|
||||||
|
|
||||||
class SkolaAutocomplete(autocomplete_light.AutocompleteModelBase):
|
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.encoding import force_unicode
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
|
||||||
from django_countries.fields import CountryField
|
from django_countries.fields import CountryField
|
||||||
from solo.models import SingletonModel
|
from solo.models import SingletonModel
|
||||||
|
@ -19,7 +21,6 @@ import reversion
|
||||||
|
|
||||||
from seminar.utils import roman
|
from seminar.utils import roman
|
||||||
|
|
||||||
# TODO společná báze (admin url, url, veřejné, ...)
|
|
||||||
class SeminarModelBase(models.Model):
|
class SeminarModelBase(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -54,6 +55,7 @@ class Skola(SeminarModelBase):
|
||||||
db_table = 'seminar_skoly'
|
db_table = 'seminar_skoly'
|
||||||
verbose_name = u'Škola'
|
verbose_name = u'Škola'
|
||||||
verbose_name_plural = u'Školy'
|
verbose_name_plural = u'Školy'
|
||||||
|
ordering = ['mesto', 'nazev']
|
||||||
|
|
||||||
# Interní ID
|
# Interní ID
|
||||||
id = models.AutoField(primary_key = True)
|
id = models.AutoField(primary_key = True)
|
||||||
|
@ -229,6 +231,16 @@ class Rocnik(SeminarModelBase):
|
||||||
def verejne_url(self):
|
def verejne_url(self):
|
||||||
return reverse('seminar_rocnik', kwargs={'pk': self.id})
|
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)
|
@reversion.register(ignore_duplicate_revisions=True)
|
||||||
@python_2_unicode_compatible
|
@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)
|
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):
|
def kod(self):
|
||||||
return u'%s.%s' % (self.rocnik.rocnik, self.cislo)
|
return u'%s.%s' % (self.rocnik.rocnik, self.cislo)
|
||||||
kod.short_description = u'Kód čísla'
|
kod.short_description = u'Kód čísla'
|
||||||
|
|
||||||
def __str__(self):
|
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):
|
def verejne(self):
|
||||||
return self.verejne_db
|
return self.verejne_db
|
||||||
|
@ -294,6 +311,7 @@ class Problem(SeminarModelBase):
|
||||||
db_table = 'seminar_problemy'
|
db_table = 'seminar_problemy'
|
||||||
verbose_name = u'Problém'
|
verbose_name = u'Problém'
|
||||||
verbose_name_plural = u'Problémy'
|
verbose_name_plural = u'Problémy'
|
||||||
|
ordering = ['nazev']
|
||||||
|
|
||||||
# Interní ID
|
# Interní ID
|
||||||
id = models.AutoField(primary_key = True)
|
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)
|
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)
|
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)'))
|
u'"DOZ:xxx" (MAMOPER.MM_DOZ), "ZAD:rocnik.cislo.uloha.typ" (MAMOPER.MM_ZADANIA), "ULOHA:xxx" (MAMOPER.MM_ULOHY)'))
|
||||||
|
|
||||||
def __str__(self):
|
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):
|
def kod_v_rocniku(self):
|
||||||
if self.typ == self.TYP_ULOHA:
|
if self.typ == self.TYP_ULOHA:
|
||||||
|
@ -379,7 +397,7 @@ class Reseni(SeminarModelBase):
|
||||||
db_table = 'seminar_reseni'
|
db_table = 'seminar_reseni'
|
||||||
verbose_name = u'Řešení'
|
verbose_name = u'Řešení'
|
||||||
verbose_name_plural = u'Řešení'
|
verbose_name_plural = u'Řešení'
|
||||||
ordering = ['problem', 'resitel']
|
ordering = ['problem_id', 'resitel_id']
|
||||||
|
|
||||||
# Interní ID
|
# Interní ID
|
||||||
id = models.AutoField(primary_key = True)
|
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)
|
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,
|
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):
|
def __str__(self):
|
||||||
return force_unicode(u"%s: %s (%sb)" % (self.resitel.plne_jmeno(), self.problem.nazev, self.body))
|
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
|
# PrilohaReseni method
|
||||||
|
@ -418,7 +437,7 @@ def generate_filename(self, filename):
|
||||||
fname = "%s_%s" % (
|
fname = "%s_%s" % (
|
||||||
timezone.now().strftime('%Y-%m-%d-%H:%M'),
|
timezone.now().strftime('%Y-%m-%d-%H:%M'),
|
||||||
clean)
|
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)
|
@reversion.register(ignore_duplicate_revisions=True)
|
||||||
|
@ -474,10 +493,10 @@ class Soustredeni(SeminarModelBase):
|
||||||
help_text=u'Místo (název obce, volitelně též objektu')
|
help_text=u'Místo (název obce, volitelně též objektu')
|
||||||
|
|
||||||
ucastnici = models.ManyToManyField(Resitel, verbose_name=u'účastníci soustředění',
|
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):
|
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):
|
def verejne(self):
|
||||||
return self.verejne_db
|
return self.verejne_db
|
||||||
|
@ -487,6 +506,30 @@ class Soustredeni(SeminarModelBase):
|
||||||
return reverse('seminar_soustredeni', kwargs={'pk': self.id})
|
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
|
@python_2_unicode_compatible
|
||||||
class VysledkyBase(SeminarModelBase):
|
class VysledkyBase(SeminarModelBase):
|
||||||
|
|
||||||
|
@ -507,6 +550,7 @@ class VysledkyBase(SeminarModelBase):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return force_unicode(u"%s: %sb (%s)" % (self.resitel.plne_jmeno(), self.body, str(self.cislo)))
|
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
|
@python_2_unicode_compatible
|
||||||
class VysledkyZaCislo(VysledkyBase):
|
class VysledkyZaCislo(VysledkyBase):
|
||||||
|
@ -517,6 +561,7 @@ class VysledkyZaCislo(VysledkyBase):
|
||||||
managed = False
|
managed = False
|
||||||
|
|
||||||
def __str__(self):
|
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)))
|
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')
|
body_celkem = models.IntegerField(u'body celkem do čísla', db_column='body_celkem')
|
||||||
|
|
||||||
def __str__(self):
|
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)))
|
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'^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'^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'^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'^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'),
|
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.http import HttpResponseRedirect
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.views import generic
|
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):
|
def AktualniZadaniView(request):
|
||||||
|
@ -16,6 +16,10 @@ class RocnikView(generic.DetailView):
|
||||||
model = Rocnik
|
model = Rocnik
|
||||||
template_name = 'seminar/rocnik.html'
|
template_name = 'seminar/rocnik.html'
|
||||||
|
|
||||||
|
class SoustredeniView(generic.DetailView):
|
||||||
|
model = Soustredeni
|
||||||
|
template_name = 'seminar/soustredeni.html'
|
||||||
|
|
||||||
class ProblemView(generic.DetailView):
|
class ProblemView(generic.DetailView):
|
||||||
model = Problem
|
model = Problem
|
||||||
template_name = 'seminar/problem.html'
|
template_name = 'seminar/problem.html'
|
||||||
|
|
Loading…
Reference in a new issue