class PartnersPage(FixUrlMixin, Page): title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") body_sk = StreamField( [ ( "partner", blocks.StructBlock( [ ("logo", ImageChooserBlock()), ("description", blocks.RichTextBlock()), ] ), ), ] ) body_en = StreamField( [ ( "partner", blocks.StructBlock( [ ("logo", ImageChooserBlock()), ("description", blocks.RichTextBlock()), ] ), ), ] ) body = TranslatedField("body_sk", "body_en") content_panels_sk = Page.content_panels + [ StreamFieldPanel("body_sk"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), StreamFieldPanel("body_en"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) festival = self.get_ancestors().type(FestivalPage).first() if festival: context["header_festival"] = festival.specific else: context["header_festival"] = last_festival(self) return context
class PodcastPage(FixUrlMixin, Page): title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=False, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") description_sk = RichTextField(blank=True) description_en = RichTextField(blank=True) description = TranslatedField("description_sk", "description_en") episodes = StreamField( [ ( "episode", blocks.StructBlock( [ ("number", blocks.IntegerBlock(min_value=1)), ("title_sk", blocks.CharBlock()), ("title_en", blocks.CharBlock()), ("category", SnippetChooserBlock("home.Category")), ("url_anchor", blocks.URLBlock()), ("url_apple", blocks.URLBlock()), ("url_spotify", blocks.URLBlock()), ] ), ), ] ) content_panels = [ FieldPanel("title", classname="full title", heading="Title SK"), FieldPanel("title_en", classname="full title", heading="Title EN"), FieldPanel("description_sk", classname="full"), FieldPanel("description_en", classname="full"), ] episodes_panel = [ StreamFieldPanel("episodes"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels, heading=_("Content")), ObjectList(episodes_panel, heading=_("Episodes")), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) return context
class ContactPage(FixUrlMixin, Page): title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") left_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="l_img+", ) left_text_sk = RichTextField(blank=True, null=True) left_text_en = RichTextField(blank=True, null=True) left_text = TranslatedField("left_text_sk", "left_text_en") right_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="r_img+", ) right_text_sk = RichTextField(blank=True, null=True) right_text_en = RichTextField(blank=True, null=True) right_text = TranslatedField("right_text_sk", "right_text_en") content_panels_sk = Page.content_panels + [ ImageChooserPanel("left_image"), FieldPanel("left_text_sk", classname="full"), ImageChooserPanel("right_image"), FieldPanel("right_text_sk", classname="full"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), FieldPanel("left_text_en", classname="full"), FieldPanel("right_text_en", classname="full"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) return context
class Location(models.Model): title_sk = models.CharField(default="", max_length=255) title_en = models.CharField(default="", max_length=255) url_to_map = models.URLField( verbose_name=_("URL to map"), help_text=_("URL to Google Maps or similar service"), ) title = TranslatedField("title_sk", "title_en") panels = [ FieldPanel("title_sk"), FieldPanel("title_en"), FieldPanel("url_to_map") ] autocomplete_search_field = "title_sk" objects = LocationManager() class Meta: verbose_name = _("location") verbose_name_plural = _("locations") def __str__(self): return self.title_sk def autocomplete_label(self): return self.title_sk
class MenuItem(Orderable): page = ParentalKey("home.FestivalPage", on_delete=models.CASCADE, related_name="menu_items") title_sk = models.CharField(max_length=32) title_en = models.CharField(max_length=32) title = TranslatedField("title_sk", "title_en") link = models.CharField(max_length=255)
class DonatePage(FixUrlMixin, Page): title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") body_sk = StreamField( [ ("heading", blocks.CharBlock(classname="title")), ("paragraph", blocks.RichTextBlock()), ] ) body_en = StreamField( [ ("heading", blocks.CharBlock(classname="title")), ("paragraph", blocks.RichTextBlock()), ] ) body = TranslatedField("body_sk", "body_en") content_panels_sk = Page.content_panels + [ StreamFieldPanel("body_sk"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), StreamFieldPanel("body_en"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) return context
class CrowdfundingRocket2Page(FixUrlMixin, Page): class Meta: verbose_name = "crowdfunding - rocket 2" title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) target_amount = models.IntegerField() title_translated = TranslatedField("title", "title_en") body_sk = StreamField([("text", blocks.TextBlock())]) body_en = StreamField([("text", blocks.TextBlock())]) body = TranslatedField("body_sk", "body_en") content_panels_sk = Page.content_panels + [ FieldPanel("target_amount"), StreamFieldPanel("body_sk"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), StreamFieldPanel("body_en"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) festival = self.get_ancestors().type(FestivalPage).first() if festival: context["festival"] = festival.specific else: context["festival"] = last_festival(self) return context
class PartnerSectionBlock(blocks.StructBlock): title_sk = blocks.CharBlock() title_en = blocks.CharBlock() title = TranslatedField("title_sk", "title_en") partners = blocks.ListBlock(PartnerBlock) class Meta: template = "home/blocks/partner_section.html" def get_context(self, value, parent_context=None): context = super().get_context(value, parent_context) if translation.get_language() == "en": context["translated_title"] = value["title_en"] else: context["translated_title"] = value["title_sk"] return context
class ProgramIndexPage(FixUrlMixin, Page): title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") content_panels_sk = Page.content_panels content_panels_en = [ FieldPanel("title_en", classname="full title"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) subpage_types = [] def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) parent_festival = FestivalPage.objects.get(pk=self.get_parent().pk) context["header_festival"] = parent_festival events = ( ArchiveQueryset() .events() .filter( date_and_time__date__gte=parent_festival.start_date, date_and_time__date__lte=parent_festival.end_date, ) .order_by("date_and_time") ) # TODO use iterator context["grouped_events"] = { k: list(v) for k, v in itertools.groupby(events, lambda e: e.date_and_time.date()) } if self.get_parent().slug == "bhd-online": context["message_empty"] = "Program prvého BHD ONLINE už čoskoro…" return context
class EventIndexPage(RoutablePageMixin, FixUrlMixin, Page): """Archive of all events""" title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") content_panels = Page.content_panels + [FieldPanel("intro", classname="full")] subpage_types = ["home.Event"] content_panels_sk = Page.content_panels content_panels_en = [ FieldPanel("title_en", classname="full title"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) @route(r"^(\d+)/(.+)/") def event_with_id_in_url(self, request, event_id, slug): event = Event.objects.get(event_id=event_id) if slug == event.slug: return event.serve(request) return redirect(event.get_url(request)) @route(r"^json/$") def json_index(self, request): return JsonResponse(ArchiveQueryset().json()) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) context["events"] = ArchiveQueryset().events() # context["events_json"] = ArchiveQueryset().json() return context
class Category(models.Model): title_sk = models.CharField(max_length=30) title_en = models.CharField(max_length=30) color = models.CharField(max_length=20) title = TranslatedField("title_sk", "title_en") panels = [ FieldPanel("title_sk"), FieldPanel("title_en"), FieldPanel("color") ] autocomplete_search_field = "title_sk" objects = CategoryManager() class Meta: verbose_name = _("category") verbose_name_plural = _("categories") def __str__(self): return self.title_sk def autocomplete_label(self): return self.title_sk
class Event(FixUrlMixin, Page): event_id = models.IntegerField(unique=True, null=True, blank=True, default=None) title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_( "The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") short_overview_sk = models.CharField( max_length=255, blank=True, ) short_overview_en = models.CharField( max_length=255, blank=True, ) short_overview = TranslatedField("short_overview_sk", "short_overview_en") description_sk = RichTextField(blank=True) description_en = RichTextField(blank=True) description = TranslatedField("description_sk", "description_en") date_and_time = models.DateTimeField(default=timezone.now, verbose_name=_("date and time")) location = models.ForeignKey( "home.Location", null=True, blank=True, on_delete=models.SET_NULL, ) video_url = models.URLField( null=True, blank=True, help_text=format_html( _("Supports Youtube, Vimeo and {}{}{}"), mark_safe( "<a href='https://github.com/wagtail/wagtail/blob/master/" "wagtail/embeds/oembed_providers.py' target='_blank'>"), _("other websites"), mark_safe("</a>"), ), ) ticket_url = models.URLField(null=True, blank=True) category = models.ForeignKey( "home.Category", null=True, blank=True, on_delete=models.SET_NULL, ) icon = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) show_on_festivalpage = models.BooleanField(default=False) wordpress_url = models.CharField(max_length=255, unique=True, null=True, blank=True) related_festival = models.ForeignKey( "home.FestivalPage", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) content_panels_sk = Page.content_panels + [ MultiFieldPanel([ FieldPanel("date_and_time"), AutocompletePanel("location"), FieldPanel("category"), PageChooserPanel("related_festival", "home.FestivalPage"), ImageChooserPanel("icon"), ]), MultiFieldPanel( [ FieldPanel("short_overview_sk"), FieldPanel("description_sk"), FieldPanel("video_url"), FieldPanel("ticket_url"), ], heading=_("description"), ), InlinePanel("speaker_connections", heading="speakers"), InlinePanel("host_connections", heading="hosts"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), MultiFieldPanel( [FieldPanel("short_overview_en"), FieldPanel("description_en")], heading=_("description"), ), ] promote_panels = Page.promote_panels + [ FieldPanel("show_on_festivalpage"), ] edit_handler = TabbedInterface([ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ]) parent_page_types = ["home.EventIndexPage"] subpage_types = [] class Meta: verbose_name = _("event") verbose_name_plural = _("events") def get_url_parts(self, request=None): """Insert PK of object to url""" site_id, root_url, page_path = super().get_url_parts(request) page_path = page_path.split("/") page_path.insert(-2, str(self.event_id)) return site_id, root_url, "/".join(page_path) def get_context(self, request, *args, **kwargs): from home.models.pages import last_festival context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) context["today"] = timezone.now().date() return context def save(self, *args, **kwargs): if self.event_id is None: last_event_id = (Event.objects.aggregate( Max("event_id"))["event_id__max"] or 0) self.event_id = last_event_id + 1 return super().save(*args, **kwargs) @cached_property def speakers_limited(self): connections = list(self.speaker_connections.all()) return { "under_limit": [c.speaker.title for c in connections[:3]], "over_limit_count": len(connections[3:]), "over_limit_names": ", ".join(c.speaker.title for c in connections[3:]), } def delete(self, *args, **kwargs): self.unpublish(user=kwargs.get("user"))
class Speaker(FixUrlMixin, Page): speaker_id = models.IntegerField(unique=True, null=True, blank=True, default=None) first_name = models.CharField(max_length=64, blank=True) last_name = models.CharField(max_length=64) description_sk = RichTextField(blank=True) description_en = RichTextField(blank=True) description = TranslatedField("description_sk", "description_en") wordpress_url = models.CharField(max_length=255, unique=True, null=True, blank=True) photo = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) class Meta: verbose_name = _("speaker") verbose_name_plural = _("speakers") parent_page_types = ["home.SpeakerIndexPage"] content_panels_sk = Page.content_panels + [ FieldRowPanel([FieldPanel("first_name"), FieldPanel("last_name")]), ImageChooserPanel("photo"), FieldPanel("description_sk"), ] content_panels_en = Page.content_panels + [ FieldPanel("description_en"), ] edit_handler = TabbedInterface([ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ]) def get_url_parts(self, request=None): """Insert PK of object to url""" site_id, root_url, page_path = super().get_url_parts(request) page_path = page_path.split("/") page_path.insert(-2, str(self.speaker_id)) return site_id, root_url, "/".join(page_path) def save(self, *args, **kwargs): if self.speaker_id is None: last_speaker_id = (Speaker.objects.aggregate( Max("speaker_id"))["speaker_id__max"] or 0) self.speaker_id = last_speaker_id + 1 self.draft_title = f"{self.first_name} {self.last_name}".strip() self.title = self.draft_title if "updated_fields" in kwargs: kwargs["updated_fields"].append("title") return super().save(*args, **kwargs) def get_context(self, request, *args, **kwargs): from home.models.pages import last_festival context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) context["events"] = (Event.objects.filter( Q(speaker_connections__speaker=self) | Q(host_connections__speaker=self) ).distinct().live().prefetch_related( Prefetch( "icon__renditions", queryset=Rendition.objects.filter(filter_spec="fill-65x65"), ))) return context @property def full_name(self): return f"{self.first_name} {self.last_name}" def delete(self, *args, **kwargs): self.unpublish(user=kwargs.get("user"))
class StreamPage(FixUrlMixin, Page): stream_url = models.URLField(blank=True) title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") popup_email_body_sk = RichTextField(blank=True) popup_email_body_en = RichTextField(blank=True) popup_email_body = TranslatedField("popup_email_body_sk", "popup_email_body_en") popup_email_button_sk = models.CharField(max_length=100) popup_email_button_en = models.CharField(max_length=100) popup_email_button = TranslatedField( "popup_email_button_sk", "popup_email_button_en" ) popup_donation_body_sk = RichTextField(blank=True) popup_donation_body_en = RichTextField(blank=True) popup_donation_body = TranslatedField( "popup_donation_body_sk", "popup_donation_body_en" ) popup_donation_button_sk = models.CharField(max_length=100, default="") popup_donation_button_en = models.CharField(max_length=100, default="") popup_donation_button = TranslatedField( "popup_donation_button_sk", "popup_donation_button_en" ) popup_donation_button_url = models.URLField(blank=True, default="") background = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, ) google_form_url = models.URLField(blank=True) donate_button_text_sk = models.CharField(max_length=100, null=True) donate_button_text_en = models.CharField(max_length=100, null=True) donate_button_text = TranslatedField( "donate_button_text_sk", "donate_button_text_en" ) donate_button_action = models.ForeignKey( Page, on_delete=models.SET_NULL, null=True, related_name="stream_page_donate" ) slido_url = models.URLField(blank=True, verbose_name="Sli.do") content_panels_sk = Page.content_panels + [ FieldPanel("stream_url"), ImageChooserPanel("background"), FieldPanel("popup_donation_body_sk"), FieldPanel("popup_donation_button_sk"), FieldPanel("popup_donation_button_url"), FieldPanel("popup_email_body_sk"), FieldPanel("popup_email_button_sk"), FieldPanel("donate_button_text_sk"), PageChooserPanel("donate_button_action"), FieldPanel("slido_url"), ] content_panels_en = [ FieldPanel("title_en", classname="full title"), FieldPanel("popup_email_body_en"), FieldPanel("popup_email_button_en"), FieldPanel("popup_donation_body_en"), FieldPanel("popup_donation_button_en"), FieldPanel("donate_button_text_en"), ] settings_panels = Page.settings_panels + [ FieldPanel("google_form_url"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) return context
class FestivalPage(FixUrlMixin, Page): formatted_title_sk = RichTextField( default="", verbose_name=_("title"), help_text=_("Visible in header next to the logo"), ) formatted_title_en = RichTextField( default="", verbose_name=_("title"), help_text=_("Visible in header next to the logo"), ) formatted_title = TranslatedField("formatted_title_sk", "formatted_title_en") logo = models.FileField(null=True, blank=True) start_date = models.DateField( default=timezone.now, verbose_name=_("festival beginning") ) end_date = models.DateField(default=timezone.now, verbose_name=_("festival end")) place = models.CharField( max_length=50, null=True, blank=True, verbose_name=_("place") ) hero_text_sk = RichTextField(blank=True) hero_text_en = RichTextField(blank=True) hero_text = TranslatedField("hero_text_sk", "hero_text_en") hero_buttons_sk = StreamField( [ ( "hero_buttons", blocks.StructBlock( [("title", blocks.CharBlock()), ("link", blocks.CharBlock())] ), ), ], null=True, blank=True, ) hero_buttons_en = StreamField( [ ( "hero_buttons", blocks.StructBlock( [("title", blocks.CharBlock()), ("link", blocks.CharBlock())] ), ), ], null=True, blank=True, ) hero_buttons = TranslatedField("hero_buttons_sk", "hero_buttons_en") video_text_sk = RichTextField(blank=True) video_text_en = RichTextField(blank=True) video_text = TranslatedField("video_text_sk", "video_text_en") headline_sk = StreamField( [ ( "headliner", blocks.StructBlock( [ ("name", blocks.CharBlock()), ("photo", ImageChooserBlock()), ("link", blocks.PageChooserBlock()), ("description", blocks.RichTextBlock()), ] ), ), ], null=True, blank=True, ) headline_en = StreamField( [ ( "headliner", blocks.StructBlock( [ ("name", blocks.CharBlock()), ("photo", ImageChooserBlock()), ("link", blocks.PageChooserBlock()), ("description", blocks.RichTextBlock()), ] ), ), ], null=True, blank=True, ) headline = TranslatedField("headline_sk", "headline_en") partner_sections = StreamField( [("partner_section", PartnerSectionBlock())], blank=True ) content_panels_sk = [ FieldPanel( "title", heading=_("Internal title"), help_text=_("Visible only in the admin"), ), FieldPanel("formatted_title_sk"), FieldPanel("logo"), FieldRowPanel([FieldPanel("start_date"), FieldPanel("end_date")]), FieldPanel("place"), FieldPanel("hero_text_sk", classname="full"), InlinePanel("hero_images", label="Hero images"), StreamFieldPanel("hero_buttons_sk"), FieldPanel("video_text_sk", classname="full"), InlinePanel("video_invites"), StreamFieldPanel("headline_sk"), ] content_panels_en = [ FieldPanel("formatted_title_en"), FieldPanel("hero_text_en", classname="full"), StreamFieldPanel("hero_buttons_en"), FieldPanel("video_text_en", classname="full"), StreamFieldPanel("headline_en"), ] promote_panels = Page.promote_panels + [ InlinePanel("menu_items", label=_("menu")), StreamFieldPanel("partner_sections"), ] subpage_types = [ "home.ProgramIndexPage", "home.CrowdfundingPage", "home.CrowdfundingStarsPage", "home.CrowdfundingRocket2Page", "home.PartnersPage", "home.AboutFestivalPage", ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = self context["events"] = ( ArchiveQueryset() .events() .filter( date_and_time__date__gte=self.start_date, date_and_time__date__lte=self.end_date, show_on_festivalpage=True, ) .order_by("date_and_time") ) return context
class SpeakerIndexPage(RoutablePageMixin, FixUrlMixin, Page): title_en = models.CharField( verbose_name=_("title"), max_length=255, blank=True, help_text=_("The page title as you'd like it to be seen by the public"), ) title_translated = TranslatedField("title", "title_en") content_panels_sk = Page.content_panels content_panels_en = [ FieldPanel("title_en", classname="full title"), ] edit_handler = TabbedInterface( [ ObjectList(content_panels_sk, heading="Content SK"), ObjectList(content_panels_en, heading="Content EN"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ] ) subpage_types = [ "home.Speaker", ] @route(r"^(\d+)/(.+)/") def speaker_with_id_in_url(self, request, speaker_id, slug): speaker = Speaker.objects.get(speaker_id=speaker_id) if slug == speaker.slug: return speaker.serve(request) return redirect(speaker.get_url(request)) def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["header_festival"] = last_festival(self) context["speakers_by_year"] = self.get_speakers_by_year() # disable defaultdict because Django Template can't work with it context["speakers_by_year"].default_factory = None return context def get_speakers_by_year(self): speakers_by_year = defaultdict(dict) min_year = ( Event.objects.live() .only("date_and_time") .earliest("date_and_time") .date_and_time.year ) max_year = ( Event.objects.live() .only("date_and_time") .latest("date_and_time") .date_and_time.year ) festivals = FestivalPage.objects.live().order_by("-start_date").all() for year in range(max_year, min_year - 1, -1): for festival in festivals: speakers = ( Speaker.objects.live() .filter( speaker_connections__event__related_festival=festival, speaker_connections__event__date_and_time__year=year, ) .select_related("photo") .order_by("last_name") .distinct() ) if speakers.exists(): speakers_by_year[year][festival] = speakers.all() return speakers_by_year