# -*- coding: utf-8 -*-
from django.contrib import admin
from django import forms
from django.forms import widgets
from reversion.admin import VersionAdmin
from solo.admin import SingletonModelAdmin
from ckeditor_uploader.widgets import CKEditorUploadingWidget
from django.db.models import Count
from django.db import models
from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from seminar.models import Skola, Resitel, Rocnik, Cislo, Problem, Reseni, PrilohaReseni, Nastaveni, Soustredeni, Soustredeni_Ucastnici, Soustredeni_Organizatori, Novinky, Organizator, Pohadka, Konfera, Uloha
from autocomplete_light import shortcuts as autocomplete_light
class UserModelChoiceField(forms.ModelChoiceField):
u"""Vlastní ModelChoiceField pro uživatele. Zobrazí kromě loginu i jméno.
"""
def label_from_instance(self, obj):
return u"{} ({})".format(obj.get_full_name(), obj.username)
def get_form_predvypln_autora(self, request, obj=None, *args, **kwargs):
u"""get_form fce pro Adminy. Předvyplňí přihlášeného uživatele jako autora.
"""
form = super(self.__class__, self).get_form(request, *args, **kwargs)
form.base_fields['autor'].initial = request.user.id
return form
def make_set_action(atribut, hodnota, nazev):
u"""
Pomocnik pro rychle vytvareni hromadnych admin akci ktere jen nastavuji
atribut (dany jako string) na danou hodnotu.
nazev je krátký popis akce pro admin rozhraní."""
def action_f(modeladmin, request, queryset):
for obj in queryset:
assert atribut in obj.__dict__
obj.__setattr__(atribut, hodnota)
obj.save()
action_f.short_description = nazev
# Trik: je potřeba, aby se funkce různě (ale libovolně) jmenovaly,
# jinak je Django v seznamu akcí splácne do jedné
action_f.__name__ = 'action_f_%d_%d_%d' % (id(atribut), id(hodnota), id(nazev), )
return action_f
### Globální nastavení
admin.site.register(Nastaveni, SingletonModelAdmin)
### UTILS (pro verbose_name a help_text)
def field_labels(model, fieldname):
f = [i for i in model._meta.fields if i.name == fieldname][0]
return {'label': f.verbose_name.capitalize(), 'help_text': f.help_text, }
def create_modeladmin(modeladmin, model, name = None, verbose_name = None, verbose_name_plural = None):
class Meta:
proxy = True
app_label = model._meta.app_label
Meta.verbose_name = verbose_name
Meta.verbose_name_plural = verbose_name_plural
attrs = {'__module__': '', 'Meta': Meta}
newmodel = type(name, (model,), attrs)
admin.site.register(newmodel, modeladmin)
return modeladmin
### INLINES
class ResitelInline(admin.TabularInline):
model = Resitel
fields = ['jmeno', 'prijmeni', 'skola', 'mesto', 'rok_maturity', ]
readonly_fields = ['jmeno', 'prijmeni', 'skola', 'mesto', 'rok_maturity', ]
extra = 0
view_on_site = False
def has_add_permission(self, req): return False
class CisloInline(admin.TabularInline):
model = Cislo
fields = ['cislo',
'datum_vydani', 'datum_deadline', 'datum_deadline_soustredeni',
'verejne_db', 'poznamka']
readonly_fields = ['cislo']
extra = 0
formfield_overrides = {
models.TextField: {'widget': forms.TextInput},
}
view_on_site = Cislo.verejne_url
def has_add_permission(self, req): return False
class PrilohaReseniInline(admin.StackedInline):
model = PrilohaReseni
fields = ['vytvoreno', 'soubor', 'poznamka']
readonly_fields = ['vytvoreno']
formfield_overrides = {
models.TextField: {'widget': forms.TextInput},
}
view_on_site = False
extra = 0
class ProblemInline(admin.TabularInline):
model = Problem
fk_name = 'cislo_zadani'
fields = ['kod', 'nazev', 'autor', 'garant', 'opravovatele', 'stav']
formfield_overrides = {
models.TextField: {'widget': forms.TextInput},
}
view_on_site = Problem.verejne_url
extra = 0
class ReseniKProblemuInline(admin.TabularInline):
form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['resitele'], fields=['resitele'])
model = Reseni
fields = ['resitele', 'forma', 'body', 'cislo_body', 'timestamp', 'poznamka']
readonly_fields = ['timestamp']
extra = 0
formfield_overrides = {
models.TextField: {'widget': forms.TextInput},
}
view_on_site = False
def get_queryset(self, request):
qs = super(ReseniKProblemuInline, self).get_queryset(request)
return qs.select_related('problem', 'cislo_body', 'resitele')
# 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 = ['cas_doruceni', 'problem']
extra = 0
formfield_overrides = {
models.TextField: {'widget': forms.TextInput},
}
view_on_site = False
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')
class Soustredeni_OrganizatoriInline(admin.TabularInline):
form = autocomplete_light.modelform_factory(Soustredeni_Organizatori, autocomplete_fields=['organizator'], fields=['organizator'],)
model = Soustredeni_Organizatori
fields = ['organizator', 'poznamka', ]
extra = 0
formfield_overrides = {
models.TextField: {'widget': forms.TextInput},
}
def get_queryset(self, request):
qs = super(Soustredeni_OrganizatoriInline, self).get_queryset(request)
return qs.select_related('organizator', 'soustredeni')
### Resitel
class ResitelAdmin(VersionAdmin):
form = autocomplete_light.modelform_factory(Resitel, autocomplete_fields=['skola'], fields=['skola'])
fk_name = 'osoba'
fieldsets = [
(None, {'fields': ['jmeno', 'prijmeni', 'user']}),
(u'Škola', {'fields': ['skola', 'rok_maturity']}),
(u'Seminář', {'fields': ['datum_souhlasu_udaje', 'datum_souhlasu_zasilani', 'datum_prihlaseni', 'zasilat']}),
(u'Osobní údaje', {'fields': ['pohlavi_muz', 'datum_narozeni', 'email', 'telefon']}),
(u'Adresa', {'fields': ['ulice', 'mesto', 'psc', 'stat']}),
]
list_display = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__user', 'osoba__pohlavi_muz', 'skola', 'rok_maturity', 'pocet_reseni']
list_filter = ['osoba__pohlavi_muz', 'rok_maturity', 'zasilat']
search_fields = ['osoba__jmeno', 'osoba__prijmeni', 'osoba__ulice', 'osoba__mesto', 'osoba__email']
inlines = [ReseniKResiteliInline]
view_on_site = False
def osoba__jmeno(self, obj):
return obj.osoba.jmeno
def osoba__prijmeni(self, obj):
return obj.osoba.prijmeni
def osoba__user(self, obj):
return obj.osoba.user
def osoba__pohlavi_muz(self, obj):
return obj.osoba.pohlavi_muz
def osoba__ulice(self, obj):
return obj.osoba.ulice
def osoba__mesto(self, obj):
return obj.osoba.mesto
def osoba__email(self, obj):
return obj.osoba.email
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(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]
view_on_site = False
admin.site.register(Skola, SkolaAdmin)
### Cislo
class CisloAdmin(VersionAdmin):
fieldsets = [
(None, {
'fields': [
'cislo',
'rocnik',
'verejne_db',
'verejna_vysledkovka',
'faze',
'poznamka',
'pdf'
]
}),
('Data', {'fields': ['datum_vydani', 'datum_deadline',
'datum_deadline_soustredeni']}),
]
list_display = [
'kod',
'rocnik',
'cislo',
'datum_vydani',
'datum_deadline',
'verejne',
'verejna_vysledkovka'
]
list_filter = ['rocnik']
view_on_site = Cislo.verejne_url
actions = [
make_set_action('verejne_db', True, 'Zveřejnit číslo'),
make_set_action('verejne_db', False, 'Skrýt (zneveřejnit) číslo'),
make_set_action('verejna_vysledkovka', True, 'Zveřejnit výsledkovku'),
make_set_action('verejna_vysledkovka', False, 'Skrýt (zneveřejnit) výsledkovku'),
]
inlines = [ProblemInline]
def get_queryset(self, request):
qs = super(CisloAdmin, self).get_queryset(request)
return qs.select_related('rocnik')
admin.site.register(Cislo, CisloAdmin)
### Rocnik
class RocnikAdmin(VersionAdmin):
fieldsets = [
(None, {'fields': ['rocnik', 'prvni_rok', 'exportovat']}),
]
list_display = ['rocnik', 'prvni_rok', 'exportovat', 'verejne']
inlines = [CisloInline]
view_on_site = Rocnik.verejne_url
actions = [
make_set_action('exportovat', True, u'Nastavit pro AESOP export'),
make_set_action('exportovat', False, u'Skrýt pro AESOP export'),
]
admin.site.register(Rocnik, RocnikAdmin)
### PrilohaReseni
# 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(VersionAdmin):
#form = autocomplete_light.modelform_factory(Reseni, autocomplete_fields=['problem', 'resitele'], fields=['problem', 'resitele'])
fieldsets = [
(None, {'fields': ['problem', 'resitele', 'forma', 'body', 'cislo_body', 'timestamp']}),
(u'Poznámky', {'fields': ['poznamka']}),
]
readonly_fields = ['timestamp']
list_display = ['problem', 'resitele', 'forma', 'body', 'timestamp', 'cislo_body']
list_filter = ['body', 'timestamp', 'forma']
search_fields = []
inlines = [PrilohaReseniInline]
view_on_site = False
def get_queryset(self, request):
qs = super(ReseniAdmin, self).get_queryset(request)
return qs.select_related('resitele', 'problem', 'cislo_body')
admin.site.register(Reseni, ReseniAdmin)
### Pohádka
class PohadkaAdminForm(forms.ModelForm):
class Meta:
model = Pohadka
exclude = []
autor = UserModelChoiceField(User.objects.filter(is_staff=True))
uloha = forms.ModelChoiceField(
Uloha.objects.all()
)
def __init__(self, *args, **kwargs):
super(PohadkaAdminForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
# viz ProblemAdminForm.__init__
if instance and instance.pk:
if instance.uloha and instance.uloha.cislo_zadani:
if instance.uloha.cislo_zadani.faze != 'admin':
self.fields['text'].widget.attrs['readonly'] = True
class PohadkaAdmin(VersionAdmin):
form = PohadkaAdminForm
view_on_site = False
def get_kod_ulohy(self, obj):
return obj.uloha.kod_v_rocniku()
get_kod_ulohy.short_description = u'Kód úlohy'
def get_rocnik(self, obj):
return obj.uloha.cislo_zadani.rocnik.rocnik
get_rocnik.short_description = u'Ročník'
list_display = [
'__str__',
'get_rocnik',
'get_kod_ulohy',
'uloha',
'autor'
]
get_form = get_form_predvypln_autora
class PohadkaKProblemuInline(admin.TabularInline):
form = PohadkaAdminForm
model = Pohadka
exclude = []
extra = 0
admin.site.register(Pohadka, PohadkaAdmin)
### Problem
from autocomplete_light.contrib.taggit_field import TaggitField, TaggitWidget
class ProblemAdminForm(forms.ModelForm):
#text_zadani = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_zadani'))
#text_reseni = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_reseni'))
#text_org = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Problem, 'text_org'))
zamereni = TaggitField(widget=TaggitWidget('TagAutocomplete'), required=False)
autor = UserModelChoiceField(User.objects.filter(is_staff=True))
opravovatel = UserModelChoiceField(User.objects.filter(is_staff=True), required=False)
class Meta:
model = Problem
exclude = ['nadproblem']
def __init__(self, *args, **kwargs):
super(ProblemAdminForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
# Nedovol měnit název a zadání resp. řešení, pokud je cislo_zadani
# resp. cislo_reseni mimo fázi admin.
#
# Nastavení readonly fields sice vypadá lépe (nevygeneruje input tag),
# ale při ukládání změny vypíše admin nespecifikovanou chybu, která je
# způsobena zřejmě tím, že se neodešle žádná hodnota pro povinné pole
# nazev. Navíc by se smazalo nepovinné pole zadání.
#
# Toto řešení je z http://stackoverflow.com/a/325038/4786205.
#
# TODO Django 1.9: použít field s atributem disabled?
if instance and instance.pk:
if instance.cislo_zadani and instance.cislo_zadani.faze != 'admin':
# CKEditor neumí readonly ...
self.fields['text_zadani'] = forms.CharField(
widget=forms.Textarea,
required=False
)
for f in ['nazev', 'text_zadani', 'body']:
self.fields[f].widget.attrs['readonly'] = True
if instance.cislo_reseni and instance.cislo_reseni.faze != 'admin':
self.fields['text_reseni'] = forms.CharField(
widget=forms.Textarea,
required=False
)
self.fields['text_reseni'].widget.attrs['readonly'] = True
class ProblemAdmin(VersionAdmin):
form = ProblemAdminForm
fieldsets = [
(None, {'fields': ['nazev', 'typ', 'stav', 'autor', 'zamereni', 'body', 'timestamp', 'import_dakos_id']}),
(u'Vydání', {'fields': ['kod', 'cislo_reseni', 'opravovatel',]}),
(None, {'fields': ['text_zadani', 'text_reseni', 'text_org',]}),
]
list_select_related = True
search_fields = ['nazev', 'text_zadani', 'text_reseni', 'text_org']
view_on_site = Problem.verejne_url
ordering = ['-timestamp']
readonly_fields = ['timestamp', 'import_dakos_id']
def get_queryset(self, request):
qs = super(ProblemAdmin, self).get_queryset(request)
return qs.select_related('autor', 'opravovatel', 'cislo_zadani', 'cislo_reseni')
def pocet_reseni(self, obj):
return obj.pocet_reseni
class ProblemNavrhAdmin(ProblemAdmin):
list_display = ['nazev', 'typ', 'stav', 'autor', 'timestamp']
list_filter = ['typ', 'zamereni', 'timestamp', 'stav']
def get_queryset(self, request):
qs = super(ProblemNavrhAdmin, self).get_queryset(request)
return qs.filter(stav__in=[Problem.STAV_NAVRH, Problem.STAV_SMAZANY])
get_form = get_form_predvypln_autora
#FIXME
#create_modeladmin(ProblemNavrhAdmin, Problem, 'ProblemNavrh', verbose_name=u'Problém (návrh)', verbose_name_plural=u'Problémy (návrhy)')
class ProblemZadanyAdmin(ProblemAdmin):
list_display = [
'nazev',
'typ',
'cislo_zadani_link',
'cislo_reseni_link',
'autor',
'opravovatel',
'kod',
'verejne'
]
list_filter = [
'typ', 'zamereni', 'cislo_zadani__cislo', 'cislo_zadani__rocnik'
]
def cislo_zadani_link(self, obj):
if not obj.cislo_zadani:
return ""
return mark_safe('{}'.format(
reverse("admin:seminar_cislo_change", args=(obj.cislo_zadani.pk,)),
obj.cislo_zadani
))
cislo_zadani_link.short_description = u'Číslo zadání'
# TODO pokud se budou odkazy v adminu více používat, možná by se hodilo je
# nějak zjednodušit, např. tímto?
# https://github.com/gitaarik/django-admin-relation-links
def cislo_reseni_link(self, obj):
if not obj.cislo_reseni:
return ""
return mark_safe('{}'.format(
reverse("admin:seminar_cislo_change", args=(obj.cislo_reseni.pk,)),
obj.cislo_reseni
))
cislo_reseni_link.short_description = u'Číslo řešení'
def get_inline_instances(self, request, obj=None):
if obj and obj.typ == Problem.TYP_ULOHA:
inlines = [ReseniKProblemuInline, PohadkaKProblemuInline]
else:
inlines = [ReseniKProblemuInline]
return [inline(self.model, self.admin_site) for inline in inlines]
def get_queryset(self, request):
qs = super(ProblemZadanyAdmin, self).get_queryset(request)
return qs.filter(stav=Problem.STAV_ZADANY)
get_form = get_form_predvypln_autora
#FIXME
#create_modeladmin(ProblemZadanyAdmin, Problem, 'ProblemZadany', verbose_name=u'Problém (zadaný)', verbose_name_plural=u'Problémy (zadané)')
#admin.site.register(Problem, ProblemAdmin)
### Prispevek (k tematkum)
#class PrispevekAdminForm(forms.ModelForm):
# text_org = forms.CharField(widget=CKEditorUploadingWidget(), required=False,
# **field_labels(Prispevek, 'text_org'))
# text_resitel = forms.CharField(widget=CKEditorUploadingWidget(), required=False,
# **field_labels(Prispevek, 'text_resitel'))
#
# class Meta:
# model = Prispevek
# exclude = []
#
#class PrispevekAdmin(VersionAdmin):
# form = PrispevekAdminForm
# list_display = ['nazev', 'problem', 'reseni', 'zverejnit']
#
#admin.site.register(Prispevek, PrispevekAdmin)
### Soustredeni
class SoustredeniAdminForm(forms.ModelForm):
text = forms.CharField(widget=CKEditorUploadingWidget(), required=False, **field_labels(Soustredeni, 'text'))
class Meta:
model = Soustredeni
exclude = []
class SoustredeniAdmin(VersionAdmin):
form = SoustredeniAdminForm
fieldsets = [
(None, {'fields': ['rocnik', 'misto', 'typ', 'verejne_db', 'exportovat', 'text']}),
('Data', {'fields': ['datum_zacatku', 'datum_konce']}),
]
list_display = ['rocnik', 'misto', 'datum_zacatku', 'typ', 'exportovat', 'verejne']
inlines = [Soustredeni_UcastniciInline, Soustredeni_OrganizatoriInline]
list_filter = ['typ', 'rocnik']
view_on_site = Soustredeni.verejne_url
actions = [
make_set_action('verejne_db', True, u'Zveřejnit soustředění'),
make_set_action('verejne_db', False, u'Skrýt (zneveřejnit) soustředění'),
make_set_action('exportovat', True, u'Nastavit pro AESOP export'),
make_set_action('exportovat', False, u'Skrýt pro AESOP export'),
]
admin.site.register(Soustredeni, SoustredeniAdmin)
### Konfery
class KonferaAdminForm(forms.ModelForm):
class Meta:
model=Konfera
exclude = []
class KonferaAdmin(VersionAdmin):
form = KonferaAdminForm
list_filter = ['soustredeni']
list_display = ['nazev','soustredeni','organizator','typ_prezentace']
# inlines = [Konfera_UcastniciInline]
admin.site.register(Konfera,KonferaAdmin)
### Novinky
class NovinkyAdminForm(forms.ModelForm):
text = forms.CharField(widget=CKEditorUploadingWidget(), required=False,
**field_labels(Novinky, 'text'))
autor = UserModelChoiceField(User.objects.filter(is_staff=True))
class Meta:
model = Novinky
exclude = []
def zverejnit_novinky(modeladmin, request, queryset):
''' zverejni vybrane novinky '''
for novinka in queryset:
novinka.zverejneno = True
novinka.save()
zverejnit_novinky.short_description = 'Zveřejnit vybané novinky'
def zneverejnit_novinky(modeladmin, request, queryset):
''' zneverejni vybrane novinky'''
for novinka in queryset:
novinka.zverejneno = False
novinka.save()
zneverejnit_novinky.short_description = 'Zneveřejnit vybrané novinky'
class NovinkyAdmin(VersionAdmin):
form = NovinkyAdminForm
list_display = ['datum', 'autor', 'text', 'zverejneno', 'obrazek']
actions = [zverejnit_novinky, zneverejnit_novinky]
get_form = get_form_predvypln_autora
admin.site.register(Novinky, NovinkyAdmin)
### Organizator
def jmeno_organizatora(obj):
''' vraci jmeno organizatora '''
jmeno = obj.user.first_name
if obj.prezdivka:
jmeno = jmeno + ' "' + obj.prezdivka + '"'
jmeno = jmeno + ' ' + obj.user.last_name
if jmeno == ' ': # zobrazeni bezejmennych orgu
return 'org'
return jmeno
jmeno_organizatora.short_description = 'Jméno organizátora'
def je_organizator_aktivni(obj):
''' zjisti, zda-li je organizator aktivni '''
return obj.user.is_active
je_organizator_aktivni.short_description = 'Aktivní'
je_organizator_aktivni.boolean = True
def zaktivovat_organizatory(modeladmin, request, queryset):
''' vybrane organizatory oznaci jako aktivni '''
for org in queryset:
org.user.is_active = True
org.user.save()
zaktivovat_organizatory.short_description = 'Zaktivovat organizátory'
def deaktivovat_organizatory(modeladmin, request, queryset):
''' deaktivuje vybrane organizatory '''
for org in queryset:
org.user.is_active = False
org.user.save()
deaktivovat_organizatory.short_description = 'Deaktivovat organizátory'
@admin.register(Organizator)
class OrganizatorAdmin(VersionAdmin):
list_filter = ['organizuje_do']
list_display = [jmeno_organizatora, je_organizator_aktivni,]
actions = [zaktivovat_organizatory, deaktivovat_organizatory,]