Forked from
TO / Maják
1814 commits behind the upstream repository.
-
jan.bednarik authoredjan.bednarik authored
models.py 11.77 KiB
from django.db import models
from django.utils.translation import gettext_lazy
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import TaggedItemBase
from wagtail.admin.edit_handlers import (
FieldPanel,
HelpPanel,
InlinePanel,
MultiFieldPanel,
ObjectList,
StreamFieldPanel,
TabbedInterface,
)
from wagtail.core import blocks
from wagtail.core.fields import RichTextField, StreamField
from wagtail.core.models import Page
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtailmetadata.models import MetadataPageMixin
class SearchCharacteristic(models.Model):
""" Ciselnik charakteristik odesilanych uzivatelem, napriklad vek65+ """
name = models.CharField("Název", max_length=200, blank=False, null=False)
# mapování chareakteristiky na přislusnou POST promennou odeslanou HTML formularem
form_param = models.CharField(
"ID parametru ve formuláři", max_length=20, blank=True, null=True
)
def __str__(self):
return self.name
class CharacteristicWeight(models.Model):
""" Prirazeni vahy jedntlivych charakteristik programovym blokum """
search_characteristic = models.ForeignKey(
SearchCharacteristic, on_delete=models.CASCADE, verbose_name="Zadáno"
)
program_point = ParentalKey(
"Program2021PointPage",
on_delete=models.CASCADE,
related_name="program_point_link",
)
weight = models.IntegerField(verbose_name="Váha")
panels = [
FieldPanel("search_characteristic"),
FieldPanel("weight"),
]
class Program2021HomePage(Page):
### FIELDS
headline = models.CharField(
"název programu",
max_length=100,
blank=True,
null=True,
help_text="Hlavní titulek domovské stránky",
)
perex = models.TextField(
"perex",
max_length=512,
blank=True,
null=True,
help_text="Text pod titulkem",
)
### PANELS
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("headline"),
FieldPanel("perex"),
],
heading="Vyhledávací formulář",
),
]
settings_panels = []
### RELATIONS
subpage_types = ["program2021.Program2021PointPage"]
### OTHERS
class Meta:
verbose_name = "Program 2021"
def get_context(self, request):
context = super().get_context(request)
if request.method == "POST":
sent_tags = [request.POST.get(x, None) for x in request.POST.keys()]
sent_tags = [x for x in sent_tags if x]
# dopocitej vahu podle predanych parametru z vyhledavani...
context["points"] = self.get_children().live().specific()
for point in context["points"]:
point.weight = point.get_weight(sent_tags)
# ...a setrid dle ni vysledky. HACK: pomale, ale pocitame max. v desitkach zaznamu, tedy acceptable
context["points"] = sorted(context["points"], key=lambda x: -x.weight)
else:
# neformular - vrat vsechny body
context["points"] = self.get_children().live().specific()
return context
class Program2021PointPageTag(TaggedItemBase):
content_object = ParentalKey(
"program2021.Program2021PointPage", on_delete=models.CASCADE
)
class Program2021PointPage(Page, MetadataPageMixin):
RICH_TEXT_FEATURES = ["bold", "italic", "ol", "ul", "link", "document-link"]
### FIELDS
public_title = models.CharField(
"veřejný název",
max_length=46,
blank=True,
null=True,
help_text="Navrhují markeťáci. Max 46 znaků.",
)
code = models.CharField(
"kód",
max_length=20,
blank=True,
null=True,
help_text="Ideálně jedno nebo dvě slova ke krátkému neformálnímu označení tématu. Max 20 znaků.",
)
annotation = models.TextField(
"anotace",
max_length=140,
blank=True,
null=True,
help_text="Text anotace by měl jasně prezentovat přínos a být dostatečně konkrétní, a to i když konkrétní parametr může být předmětem podrobnějších analýz a diskuse. Anotace má až na výjimky obsahovat konkrétní číslo reprezentující rozsah problému nebo přínos jeho řešení (v tomto případě ušetření 4 miliard). Tato část bodu společně s veřejným názvem je schvalována republikovým výborem jako závazný program do voleb. Max 140 znaků.",
)
problem = models.TextField(
"problém",
max_length=280,
blank=True,
null=True,
help_text="Stručné vystižení podstaty problému ve vztahu k celé společnosti a klíčové cílové skupině. Může jít o budoucí hrozbu, náklady na odkládání či dosud nevyužitou příležitost. Max 280 znaků",
)
ideal = models.TextField(
"ideál", max_length=280, blank=True, null=True, help_text="Max 280 znaků."
)
benefits_self_employed = models.TextField(
"benefity OSVČ",
max_length=250,
blank=True,
null=True,
help_text="Stručný popis dopadu na danou cílovou skupinu. Max 140 znaků.",
)
benefits_companies = models.TextField(
"benefity firmy",
max_length=250,
blank=True,
null=True,
help_text="Stručný popis dopadu na danou cílovou skupinu. Max 140 znaků.",
)
benefits_public_money = models.TextField(
"benefity veřejné finance",
max_length=250,
blank=True,
null=True,
help_text="Rozpracuje tým finance. Úkolem finančního týmu není zpracovat to, ale dát k tomu metodiku a metodickou pomoc. V případě žádosti o pomoc se obracejte prosím na finančního analytika poslaneckého klubu Tomáše Kopečného. Max 140 znaků.",
)
already_done = RichTextField(
"co jsme už udělali",
max_length=1800,
blank=True,
null=True,
help_text="Max 1800 znaků.",
features=RICH_TEXT_FEATURES,
)
proposals = RichTextField(
"navrhovaná opatření",
max_length=1800,
blank=True,
null=True,
help_text="Konkrétní (!) body specifikující náš postup v chronologickém pořadí. Max 1800 znaků.",
features=RICH_TEXT_FEATURES,
)
implementation_time = models.CharField(
"časový horizont realizace",
max_length=20,
blank=True,
null=True,
help_text="Doba, po které se projekt převede do standardního procesního řízení a lze vyhodnotit přinášený efekt. Jde pouze o realizační fázi, nikoliv celý životní cyklus.",
)
faq = StreamField(
[
(
"item",
blocks.StructBlock(
[
("question", blocks.CharBlock(label="otázka")),
("answer", blocks.TextBlock(label="odpověď")),
],
label="dotaz",
),
),
],
verbose_name="často kladené dotazy",
blank=True,
)
sources = RichTextField(
"zdroje",
blank=True,
null=True,
help_text="Naše vlastní údaje (odhady), které nevycházejí přímo z renomovaného zdroje, dokládáme vlastními analýzami na dané téma, které jsou v seznamu zdrojů a měly by procházet externí oponenturou.",
features=RICH_TEXT_FEATURES,
)
related = StreamField(
[
(
"point",
blocks.PageChooserBlock(
label="programový bod", page_type="program2021.Program2021PointPage"
),
),
],
verbose_name="související body",
blank=True,
)
image_title = models.ForeignKey(
"wagtailimages.Image",
verbose_name="titulní obrázek",
on_delete=models.PROTECT,
null=True,
blank=True,
)
images = StreamField(
[
(
"item",
blocks.StructBlock(
[
("image", ImageChooserBlock(label="ilustrační obrázek")),
("title", blocks.CharBlock(label="popis")),
],
label="obrázek",
),
),
],
verbose_name="ilustrační obrázky",
blank=True,
)
owner_name = models.TextField(
"jméno garanta (zodpovědné osoby)", max_length=250, blank=True, null=True
)
owner_url = models.URLField("odkaz na garanta", blank=True, null=True)
tags = ClusterTaggableManager(through=Program2021PointPageTag, blank=True)
### PANELS
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("public_title"),
FieldPanel("annotation"),
FieldPanel("tags"),
FieldPanel("problem"),
FieldPanel("ideal"),
FieldPanel("already_done"),
FieldPanel("proposals"),
FieldPanel("sources"),
FieldPanel("implementation_time"),
FieldPanel("code"),
ImageChooserPanel("image_title"),
],
heading="základní informace",
),
MultiFieldPanel(
[FieldPanel("owner_name"), FieldPanel("owner_url")],
heading="garant",
),
StreamFieldPanel("images"),
StreamFieldPanel("related"),
]
benefits_content_panels = [
HelpPanel(
"V této části rozpracováváme benefity tak, abychom je mohli souhrnně nabídnout dané cílové skupině. Negativní věci zpracováváme typicky do často kladených otázek dole. U negativ se však vždy prezentuje i související přínos (tzv. balíčkovací zásada, např. snížíme daně z práce díky lepšímu zdanění zisků dnes vyváděných do zahraničí), aby nikdo nemohl takový bod vytrhnout z kontextu a prezentovat proti nám."
),
MultiFieldPanel(
[
FieldPanel("benefits_self_employed"),
FieldPanel("benefits_companies"),
FieldPanel("benefits_public_money"),
]
),
]
faq_content_panels = [
StreamFieldPanel("faq"),
]
search_panels = [InlinePanel("program_point_link", label="Váhy vyhledávání")]
promote_panels = [
MultiFieldPanel(
[
FieldPanel("slug"),
FieldPanel("seo_title"),
FieldPanel("search_description"),
ImageChooserPanel("search_image"),
],
gettext_lazy("Common page configuration"),
),
]
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading=gettext_lazy("Content")),
ObjectList(benefits_content_panels, heading="Benefity"),
ObjectList(search_panels, heading="Hledání"),
ObjectList(faq_content_panels, heading="FAQ"),
ObjectList(promote_panels, heading=gettext_lazy("Promote")),
]
)
### RELATIONS
parent_page_types = ["program2021.Program2021HomePage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Programový bod"
def get_weight(self, param_ids):
""" Vraci celkovou vahu tagu, predanych v seznamu param_ids """
# Kvuli prehlednosti nepisu jako oneliner :)
my_weights = self.program_point_link.all()
involved_weights = [
x.weight
for x in my_weights
if x.search_characteristic.form_param in param_ids
]
return sum(involved_weights)