Select Git revision
0043_alter_donateprojectpage_form_title.py
-
Tomáš Valenta authoredTomáš Valenta authored
models.py 29.61 KiB
import random
from django.core.exceptions import ValidationError
from django.core.paginator import Paginator
from django.db import models
from django.shortcuts import render
from django.utils.translation import gettext_lazy
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import Tag, TaggedItemBase
from wagtail.admin.edit_handlers import (
FieldPanel,
HelpPanel,
MultiFieldPanel,
ObjectList,
PageChooserPanel,
StreamFieldPanel,
TabbedInterface,
)
from wagtail.admin.forms import WagtailAdminPageForm
from wagtail.contrib.table_block.blocks import TableBlock
from wagtail.core.blocks import RichTextBlock
from wagtail.core.fields import RichTextField, StreamField
from wagtail.core.models import Page
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtailmetadata.models import MetadataPageMixin
from calendar_utils.models import CalendarMixin
from shared.models import (
ArticleMixin,
ExtendedMetadataHomePageMixin,
ExtendedMetadataPageMixin,
MenuMixin,
SubpageMixin,
)
from shared.utils import make_promote_panels
from tuning import admin_help
from uniweb.constants import RICH_TEXT_FEATURES
from . import blocks
from .forms import JekyllImportForm
class DistrictHomePage(
MenuMixin, ExtendedMetadataHomePageMixin, MetadataPageMixin, CalendarMixin, Page
):
### FIELDS
subheader = StreamField(
[
("header_simple", blocks.HomepageSimpleHeaderBlock()),
("header", blocks.HomepageHeaderBlock()),
],
verbose_name="Blok pod headerem",
blank=True,
)
articles_title = models.CharField("Nadpis článků", max_length=256)
election_countdown_datetime = models.DateTimeField(
"Datum a čas pro odpočet do voleb",
null=True,
blank=True,
help_text="Pro skrytí nechte nevyplněné",
)
show_calendar_on_hp = models.BooleanField(
"Zobrazit kalendář dole na homepage", default=True
)
region_map_button_text = models.CharField(
"Text tlačítka mapy", max_length=256, default="Piráti v krajích"
)
calendar_button_text = models.CharField(
"Text tlačítka kalendáře", max_length=256, default="Kalendář"
)
custom_logo = models.ForeignKey(
"wagtailimages.Image", blank=True, null=True, on_delete=models.SET_NULL
)
show_pirati_cz_link = models.BooleanField(
"Zobrazit v záhlaví odkaz 'pirati.cz'", default=True
)
show_eshop_link = models.BooleanField(
"Zobrazit v záhlaví odkaz na pirátský eshop", default=True
)
show_magazine_link = models.BooleanField(
"Zobrazit v záhlaví odkaz na pirátské listy", default=True
)
facebook = models.URLField(
"Facebook URL",
blank=True,
null=True,
default="https://www.facebook.com/ceska.piratska.strana",
)
twitter = models.URLField(
"Twitter URL",
blank=True,
null=True,
default="https://www.twitter.com/PiratskaStrana",
)
youtube = models.URLField(
"YouTube URL",
blank=True,
null=True,
default="https://www.youtube.com/channel/UC_zxYLGrkmrYazYt0MzyVlA",
)
instagram = models.URLField(
"Instagram URL",
blank=True,
null=True,
default="https://www.instagram.com/pirati.cz/",
)
flickr = models.URLField(
"Flickr URL",
blank=True,
null=True,
default="https://www.flickr.com/photos/pirati/",
)
forum = models.URLField(
"Fórum URL", blank=True, null=True, default="https://forum.pirati.cz/"
)
contact_email = models.EmailField("kontaktni email", max_length=250, blank=True)
contact_phone = models.TextField("kontaktni telefon", max_length=250, blank=True)
contact_newcomers = models.URLField(
"URL pro zájemce o členství",
blank=True,
null=True,
default="https://nalodeni.pirati.cz",
)
donation_page = models.URLField(
"URL pro příjem darů (tlačítko Přispěj)",
blank=True,
null=True,
default="https://dary.pirati.cz",
)
# Lide uvedeni v paticce
footperson_coord_title = models.CharField(
"Název funkce", max_length=128, default="Koordinátor"
)
footperson_coord = models.ForeignKey(
"district.DistrictPersonPage",
verbose_name="Koordinátor",
on_delete=models.PROTECT,
null=True,
blank=True,
related_name="+",
)
footperson_electman_title = models.CharField(
"Název funkce", max_length=128, default="Volební manažer"
)
footperson_electman = models.ForeignKey(
"district.DistrictPersonPage",
verbose_name="Volební manažer",
on_delete=models.PROTECT,
null=True,
blank=True,
related_name="+",
)
footperson_media_title = models.CharField(
"Název funkce", max_length=128, default="Kontakt pro média"
)
footperson_media = models.ForeignKey(
"district.DistrictPersonPage",
verbose_name="Kontakt pro média",
on_delete=models.PROTECT,
null=True,
blank=True,
related_name="+",
)
# settings
matomo_id = models.IntegerField(
"Matomo ID pro sledování návštěvnosti", blank=True, null=True
)
fallback_image = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
null=True,
related_name="+",
)
### PANELS
content_panels = Page.content_panels + [
StreamFieldPanel("subheader"),
FieldPanel("articles_title"),
FieldPanel("election_countdown_datetime"),
FieldPanel("show_calendar_on_hp"),
]
promote_panels = make_promote_panels(admin_help.build(admin_help.IMPORTANT_TITLE))
settings_panels = [
ImageChooserPanel("custom_logo"),
FieldPanel("matomo_id"),
FieldPanel("title_suffix"),
MultiFieldPanel(
[
FieldPanel("show_pirati_cz_link"),
FieldPanel("show_eshop_link"),
FieldPanel("show_magazine_link"),
FieldPanel("donation_page"),
FieldPanel("contact_newcomers"),
FieldPanel("facebook"),
FieldPanel("twitter"),
FieldPanel("youtube"),
FieldPanel("instagram"),
FieldPanel("flickr"),
FieldPanel("forum"),
],
gettext_lazy("Odkazy na webu"),
),
MultiFieldPanel(
[
FieldPanel("contact_email"),
FieldPanel("contact_phone"),
FieldPanel("contact_newcomers"),
],
gettext_lazy("Kontakty"),
),
MultiFieldPanel(
[
FieldPanel("footperson_coord_title"),
PageChooserPanel("footperson_coord"),
FieldPanel("footperson_electman_title"),
PageChooserPanel("footperson_electman"),
FieldPanel("footperson_media_title"),
PageChooserPanel("footperson_media"),
],
gettext_lazy("Lidé v zápatí stránky"),
),
MultiFieldPanel(
[
FieldPanel("region_map_button_text"),
FieldPanel("calendar_button_text"),
FieldPanel("calendar_url"),
],
gettext_lazy("Nastavení lišty s kalendářem a mapou"),
),
ImageChooserPanel("fallback_image"),
]
### EDIT HANDLERS
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading="Obsah"),
ObjectList(promote_panels, heading="Propagovat"),
ObjectList(settings_panels, heading="Nastavení"),
ObjectList(MenuMixin.menu_panels, heading="Menu"),
]
)
### RELATIONS
subpage_types = [
"district.DistrictArticlesPage",
"district.DistrictCenterPage",
"district.DistrictContactPage",
"district.DistrictCrossroadPage",
"district.DistrictCustomPage",
"district.DistrictElectionPage",
"district.DistrictPeoplePage",
"district.DistrictProgramPage",
"district.DistrictTagsPage",
]
### OTHERS
class Meta:
verbose_name = "Místní sdružení"
def _first_subpage_of_type(self, page_type) -> Page or None:
try:
return self.get_descendants().type(page_type).live().specific()[0]
except IndexError:
return None
@property
def articles(self):
return (
self.get_descendants()
.type(DistrictArticlePage)
.live()
.specific()
.order_by("-districtarticlepage__date")[:6]
)
@property
def articles_page(self):
return self._first_subpage_of_type(DistrictArticlesPage)
@property
def center_page(self):
return self._first_subpage_of_type(DistrictCenterPage)
@property
def contact_page(self):
return self._first_subpage_of_type(DistrictContactPage)
@property
def election_page(self):
return self._first_subpage_of_type(DistrictElectionPage)
@staticmethod
def get_404_response(request):
return render(request, "district/404.html", status=404)
@property
def people_page(self):
return self._first_subpage_of_type(DistrictPeoplePage)
@property
def program_page(self):
return self._first_subpage_of_type(DistrictProgramPage)
@property
def root_page(self):
return self
@property
def tags_page(self):
return self._first_subpage_of_type(DistrictTagsPage)
@property
def has_calendar(self):
return self.calendar_id is not None
class DistrictArticleTag(TaggedItemBase):
content_object = ParentalKey(
"district.DistrictArticlePage", on_delete=models.CASCADE
)
class DistrictArticlePage(
ArticleMixin, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
author_page = models.ForeignKey(
"district.DistrictPersonPage", on_delete=models.SET_NULL, null=True, blank=True
)
is_black = models.BooleanField("Má tmavé pozadí?", default=False)
tags = ClusterTaggableManager(through=DistrictArticleTag, blank=True)
### PANELS
content_panels = ArticleMixin.content_panels + [
FieldPanel("author_page"),
FieldPanel("is_black"),
FieldPanel("tags"),
]
promote_panels = make_promote_panels(
admin_help.build(admin_help.NO_SEO_TITLE, admin_help.NO_DESCRIPTION_USE_PEREX),
search_image=False,
)
### RELATIONS
parent_page_types = ["district.DistrictArticlesPage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Aktualita"
def get_context(self, request):
context = super().get_context(request)
context["related_articles"] = (
self.get_siblings(inclusive=False)
.live() # TODO? filtrovat na stejné tagy?
.specific()
.order_by("-districtarticlepage__date")[:3]
)
return context
class DistrictArticlesPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
last_import_log = models.TextField(
"Výstup z posledního importu", null=True, blank=True
)
max_items = models.IntegerField("Počet článků na stránce", default=12)
### PANELS
content_panels = Page.content_panels + [
FieldPanel("max_items"),
]
promote_panels = make_promote_panels()
import_panels = [
MultiFieldPanel(
[
FieldPanel("do_import"),
FieldPanel("collection"),
FieldPanel("dry_run"),
FieldPanel("use_git"),
FieldPanel("jekyll_repo_url"),
FieldPanel("readonly_log"),
HelpPanel(
"Import provádějte vždy až po vytvoření stránky aktualit. "
'Pro uložení logu je nutné volit možnost "Publikovat", nikoliv'
'pouze "Uložit koncept". '
"Import proběhne na pozadí a může trvat až několik minut. "
"Dejte si po spuštění importu kávu a potom obnovte stránku pro "
"zobrazení výsledku importu."
),
],
"import z Jekyll repozitáře",
),
]
### EDIT HANDLERS
edit_handler = TabbedInterface(
[
ObjectList(content_panels, heading="Obsah"),
ObjectList(promote_panels, heading="Propagovat"),
ObjectList(import_panels, heading="Import"),
]
)
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = ["district.DistrictArticlePage"]
### OTHERS
base_form_class = JekyllImportForm
class Meta:
verbose_name = "Aktuality"
def get_context(self, request):
context = super().get_context(request)
context["articles"] = Paginator(
self.get_children()
.live()
.specific()
.order_by("-districtarticlepage__date"),
self.max_items,
).get_page(request.GET.get("page"))
return context
class DistrictContactPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
contact_people = StreamField(
[("item", blocks.ContactItemBlock())],
verbose_name="Kontakty",
blank=True,
)
text = RichTextField("Text", blank=True, features=RICH_TEXT_FEATURES)
### PANELS
content_panels = Page.content_panels + [
StreamFieldPanel("contact_people"),
FieldPanel("text"),
]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Kontakty"
class DistrictTagsPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### PANELS
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Stránka s tagy"
def get_context(self, request, *args, **kwargs) -> dict:
context = super().get_context(request)
# Potřebujeme IDčka článků pro správnou root_page pro filtrování zobrazených
# tagů i samotných stránek, protože se filtrují přes specifický field
# (tags__slug)
site_article_ids = (
self.root_page.articles_page.get_children()
.live()
.specific()
.values_list("id", flat=True)
)
# Naplním "tag" a "article_page_list" parametry
context.update(**self.get_tag_and_articles(request, site_article_ids))
context["tag_list"] = self.get_tag_qs(site_article_ids)
# Pro obecnou paginaci posílám "extra_query", abych si podržel tag pro další GET
context["extra_query"] = "&tag={}".format(request.GET.get("tag", ""))
return context
def get_tag_and_articles(self, request, site_article_ids: list) -> dict:
"""
Vrátí vyfiltrované články podle tagu a page query pro z daného "výběru"
pro danou stránku (site_article_ids). Lepší by bylo články a tag řešit
separátně, ale pak by se musel rozpadnout ten try/except na více bloků.
"""
article_page_qs = DistrictArticlePage.objects.filter(id__in=site_article_ids)
try:
tag = DistrictArticleTag.objects.filter(tag__slug=request.GET["tag"])[0].tag
article_page_qs = article_page_qs.filter(tags__slug=tag.slug)
except (KeyError, IndexError):
tag = None
return {
"article_page_list": Paginator(
article_page_qs.order_by("-date"),
self.root_page.articles_page.max_items,
).get_page(request.GET.get("page")),
"tag": tag,
}
@staticmethod
def get_tag_qs(site_article_ids: list) -> models.QuerySet:
"""
Getuje Tagy pouze pro DistrictArticlePage omezeno IDčky getnutých přes
root_page. Počítá, kolik článků je s daným tagem.
"""
return (
Tag.objects.filter(districtarticlepage__id__in=site_article_ids)
.order_by("slug")
.annotate(count=models.Count("slug"))
.values("name", "slug", "count")
)
class DistrictPersonTag(TaggedItemBase):
content_object = ParentalKey(
"district.DistrictPersonPage", on_delete=models.CASCADE
)
class DistrictPersonPageForm(WagtailAdminPageForm):
def clean(self):
cleaned_data = super().clean()
email = cleaned_data.get("email", None)
if email:
pages_with_email = DistrictPersonPage.objects.filter(email=email)
num_pages_with_email = len(pages_with_email)
if num_pages_with_email > 1 or (
num_pages_with_email == 1 and pages_with_email[0] != self.instance
):
raise ValidationError({"email": "Stránka s tímto emailem již existuje"})
return cleaned_data
class DistrictPersonPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
base_form_class = DistrictPersonPageForm
job = models.CharField(
"Povolání",
max_length=128,
blank=True,
null=True,
help_text="Např. 'Informatik'",
)
job_function = models.CharField(
"Funkce", max_length=128, blank=True, null=True, help_text="Např. 'Předseda'"
)
background_photo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="+",
verbose_name="obrázek do záhlaví",
)
profile_photo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="+",
verbose_name="profilová fotka",
)
text = RichTextField("text", blank=True, features=RICH_TEXT_FEATURES)
email = models.EmailField("Email", null=True)
show_email = models.BooleanField("Zobrazovat email na stránce?", default=True)
phone = models.CharField("Telefon", max_length=16, blank=True, null=True)
city = models.CharField("Město/obec", max_length=64, blank=True, null=True)
age = models.IntegerField("Věk", blank=True, null=True)
is_pirate = models.BooleanField("Je členem Pirátské strany?", default=True)
facebook_url = models.URLField("Odkaz na Facebook", blank=True, null=True)
instagram_url = models.URLField("Odkaz na Instagram", blank=True, null=True)
twitter_url = models.URLField("Odkaz na Twitter", blank=True, null=True)
youtube_url = models.URLField("Odkaz na Youtube kanál", blank=True, null=True)
flickr_url = models.URLField("Odkaz na Flickr", blank=True, null=True)
custom_web_url = models.URLField("Odkaz na vlastní web", blank=True, null=True)
other_urls = StreamField(
[("other_url", blocks.PersonUrlBlock())],
verbose_name="Další odkaz",
blank=True,
)
### PANELS
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("job"),
FieldPanel("job_function"),
],
"Základní údaje",
),
MultiFieldPanel(
[
ImageChooserPanel("profile_photo"),
ImageChooserPanel("background_photo"),
],
"Fotky",
),
FieldPanel("text"),
MultiFieldPanel(
[
FieldPanel("email"),
FieldPanel("show_email"),
FieldPanel("phone"),
FieldPanel("city"),
FieldPanel("age"),
FieldPanel("is_pirate"),
],
"Kontaktní informace",
),
MultiFieldPanel(
[
FieldPanel("facebook_url"),
FieldPanel("instagram_url"),
FieldPanel("twitter_url"),
FieldPanel("youtube_url"),
FieldPanel("flickr_url"),
FieldPanel("custom_web_url"),
StreamFieldPanel("other_urls"),
],
"Sociální sítě",
),
]
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictPeoplePage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Detail osoby"
def get_background_photo(self):
"""
Vrací background_photo pro pozadí na stránce, pokud není nastaveno,
vezme falbback z homepage
"""
return (
self.background_photo
if self.background_photo
else self.root_page.fallback_image
)
def get_context(self, request):
context = super().get_context(request)
# Na strance detailu cloveka se vpravo zobrazuji 3 dalsi nahodne profily
context["random_people"] = list(
self.get_siblings(inclusive=False).live().specific()
)
random.shuffle(context["random_people"])
context["random_people"] = context["random_people"][:3]
return context
class DistrictPeoplePage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
content = StreamField(
[("people_group", blocks.PeopleGroupListBlock())],
verbose_name="Obsah stránky",
blank=True,
)
### PANELS
content_panels = Page.content_panels + [StreamFieldPanel("content")]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = ["district.DistrictPersonPage"]
### OTHERS
class Meta:
verbose_name = "Lidé"
class DistrictElectionBasePage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
text = RichTextField("text", blank=True, features=RICH_TEXT_FEATURES)
### PANELS
content_panels = Page.content_panels + [FieldPanel("text")]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictElectionPage"]
subpage_types = []
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
context["election_points"] = (
self.get_siblings().type(DistrictElectionPointPage).live().specific()
)
context["strategy_page"] = self.get_parent().specific.strategy_page
return context
class Meta:
abstract = True
class DistrictAfterElectionPage(DistrictElectionBasePage):
class Meta:
verbose_name = "Povolební strategie"
class DistrictElectionPointPage(DistrictElectionBasePage):
### FIELDS
guarantor = models.ForeignKey(
"district.DistrictPersonPage", on_delete=models.PROTECT
)
list_image = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
related_name="+",
)
perex = models.TextField("Perex", help_text="Pro přehled volebního programu")
### PANELS
content_panels = DistrictElectionBasePage.content_panels + [
PageChooserPanel("guarantor"),
ImageChooserPanel("list_image"),
FieldPanel("perex"),
]
### OTHERS
class Meta:
verbose_name = "Bod programu voleb"
class DistrictElectionPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
header = StreamField(
[("election_header_block", blocks.ElectionHeaderBlock())],
verbose_name="Obsah headeru",
blank=True,
)
content = StreamField(
[("candidate_list", blocks.CandidateListBlock())],
verbose_name="Obsah stránky",
blank=True,
)
### PANELS
content_panels = Page.content_panels + [
StreamFieldPanel("header"),
StreamFieldPanel("content"),
]
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = [
"district.DistrictElectionPointPage",
"district.DistrictAfterElectionPage",
]
### OTHERS
class Meta:
verbose_name = "Volební rozcestník"
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
context["election_points"] = (
self.get_children().live().type(DistrictElectionPointPage).specific()
)
return context
@property
def strategy_page(self):
try:
return (
self.get_descendants()
.type(DistrictAfterElectionPage)
.live()
.specific()[0]
)
except IndexError:
return None
class DistrictProgramPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
perex = models.TextField("Perex", blank=True)
content = StreamField(
[
("static_program_block", blocks.StaticProgramBlock()),
("redmine_program_block", blocks.RedmineProgramBlock()),
],
verbose_name="obsah stránky",
blank=True,
)
### PANELS
content_panels = Page.content_panels + [
FieldPanel("perex"),
StreamFieldPanel("content"),
]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Program"
def save(self, **kwargs):
from redmine_utils.functions import fill_data_from_redmine_for_page
fill_data_from_redmine_for_page(self)
return super().save(**kwargs)
class DistrictCenterPage(
CalendarMixin, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
perex = models.TextField("Perex", blank=True, null=True)
background_photo = models.ForeignKey(
"wagtailimages.Image",
on_delete=models.PROTECT,
blank=True,
null=True,
related_name="+",
)
content = StreamField(
[
("text", RichTextBlock()),
("table", TableBlock()),
],
verbose_name="Obsah",
blank=True,
)
text = RichTextField("Text", blank=True, null=True)
sidebar_content = StreamField(
[("address", blocks.AddressBlock()), ("contact", blocks.CenterContactBlock())],
verbose_name="Obsah bočního panelu",
blank=True,
)
### PANELS
content_panels = Page.content_panels + [
FieldPanel("perex"),
ImageChooserPanel("background_photo"),
FieldPanel("text"),
StreamFieldPanel("content"),
FieldPanel("calendar_url"),
StreamFieldPanel("sidebar_content"),
]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Stránka pirátského centra"
def get_background_photo(self):
"""
Vrací background_photo pro pozadí na stránce, pokud není nastaveno,
vezme falbback z homepage
"""
return (
self.background_photo
if self.background_photo
else self.root_page.fallback_image
)
@property
def has_calendar(self):
return self.calendar_id is not None
class DistrictCrossroadPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
cards_content = StreamField(
[("cards", blocks.CardLinkWithHeadlineBlock())],
verbose_name="Karty rozcestníku",
blank=True,
)
content = StreamField(
[
("people_group", blocks.PeopleGroupListBlock()),
],
verbose_name="Obsah stránky",
blank=True,
)
### PANELS
content_panels = Page.content_panels + [
StreamFieldPanel("cards_content"),
StreamFieldPanel("content"),
]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictHomePage"]
subpage_types = [
"district.DistrictAfterElectionPage",
"district.DistrictArticlePage",
"district.DistrictArticlesPage",
"district.DistrictCenterPage",
"district.DistrictContactPage",
"district.DistrictCrossroadPage",
"district.DistrictCustomPage",
"district.DistrictElectionPage",
"district.DistrictElectionPointPage",
"district.DistrictPeoplePage",
"district.DistrictPersonPage",
"district.DistrictProgramPage",
"district.DistrictTagsPage",
]
### OTHERS
class Meta:
verbose_name = "Rozcestník s kartami"
class DistrictCustomPage(
ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page
):
### FIELDS
content = StreamField(
[
("text", RichTextBlock()),
("table", TableBlock()),
("people_group", blocks.PeopleGroupListBlock()),
],
verbose_name="Obsah",
blank=True,
)
### PANELS
content_panels = Page.content_panels + [
StreamFieldPanel("content"),
]
promote_panels = make_promote_panels()
settings_panels = []
### RELATIONS
parent_page_types = ["district.DistrictHomePage", "district.DistrictCrossroadPage"]
subpage_types = []
### OTHERS
class Meta:
verbose_name = "Libovolná vlastní stránka"