class FlexPage(Page): """A flexible page class.""" # template = "cms/pages/home_page.html" subpage_types = ['pages.FlexPage'] headline = models.TextField( max_length=140, blank=True, null=True, help_text="An optional subtitle" ) banner_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=False, on_delete=models.SET_NULL, related_name="+", help_text="An optional banner image", ) body = RichTextField( null=True, blank=True, help_text='Article body' ) content = StreamField([ ('ContentBlock', ContentBlock()), ('ImageGalleryBlock', ImageGalleryBlock()), ('CallToActionBlock', CallToActionBlock()), ], null=True, blank=True) content_panels = [ FieldPanel('title', classname="full title"), FieldPanel('headline'), FieldPanel('body'), ImageChooserPanel('banner_image'), StreamFieldPanel('content'), ] graphql_fields = [ GraphQLString("headline"), GraphQLString("body"), GraphQLImage("banner_image"), GraphQLImage("banner_image_thumbnail", serializer=ImageRenditionField("fill-100x100", source="banner_image")), GraphQLStreamfield("content"), ] class Meta: """Meta information.""" verbose_name = "Page" verbose_name_plural = "Pages"
class StandardPage(BasePage): template = 'patterns/pages/standardpages/information_page.html' subpage_types = ['standardpages.StandardPage'] introduction = models.TextField(blank=True) body = StreamField(StoryBlock()) featured_image = models.ForeignKey('images.CustomImage', null=True, blank=True, related_name='+', on_delete=models.SET_NULL) featured_image_caption = models.CharField( blank=True, max_length=250, ) biography = models.CharField( help_text="Use this field to override the author's biography " "on this page.", max_length=255, blank=True) search_fields = BasePage.search_fields + [ index.SearchField('introduction'), index.SearchField('body'), ] content_panels = BasePage.content_panels + [ FieldPanel('introduction'), MultiFieldPanel( [ ImageChooserPanel('featured_image'), FieldPanel('featured_image_caption'), ], heading="Featured Image", ), StreamFieldPanel('body'), InlinePanel('authors', label="Authors"), ] # Export fields over REST API api_fields = [ APIField('introduction'), APIField('body'), APIField('featured_image', serializer=ImageRenditionField('fill-1920x1080')), APIField('featured_image_caption'), ] # Export fields over GraphQL graphql_fields = [ GraphQLString("introduction"), GraphQLStreamfield("body"), GraphQLImage("featured_image"), GraphQLString("featured_image_caption"), ] class Meta: verbose_name = "Standard Page"
class ImageGalleryImage(blocks.StructBlock): caption = blocks.CharBlock(classname="full title") image = ImageChooserBlock() graphql_fields = [ GraphQLString("caption"), GraphQLImage("image") ]
class TextAndButtonsBlock(blocks.StructBlock): text = blocks.TextBlock() buttons = blocks.ListBlock(ButtonBlock()) graphql_fields = [ GraphQLString("text"), GraphQLImage("image"), GraphQLStreamfield("buttons"), ]
class BlogPage(GrapplePageMixin, Page): author = models.CharField(max_length=255) date = models.DateField("Post date") advert = models.ForeignKey('home.Advert', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') cover = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') book_file = models.ForeignKey('wagtaildocs.Document', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') featured_media = models.ForeignKey('wagtailmedia.Media', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') body = StreamField([ ("heading", blocks.CharBlock(classname="full title")), ("paraagraph", blocks.RichTextBlock()), ("image", ImageChooserBlock()), ("decimal", blocks.DecimalBlock()), ("date", blocks.DateBlock()), ("datetime", blocks.DateTimeBlock()), ]) content_panels = Page.content_panels + [ FieldPanel("author"), FieldPanel("date"), ImageChooserPanel('cover'), StreamFieldPanel("body"), InlinePanel('related_links', label="Related links"), SnippetChooserPanel('advert'), DocumentChooserPanel('book_file'), MediaChooserPanel('featured_media'), ] graphql_fields = [ GraphQLString("heading"), GraphQLString("date"), GraphQLString("author"), GraphQLStreamfield("body"), GraphQLForeignKey("related_links", "home.blogpagerelatedlink", True), GraphQLSnippet('advert', 'home.Advert'), GraphQLImage('cover'), GraphQLDocument('book_file'), GraphQLMedia('featured_media'), ]
class TextAndButtonsBlock(blocks.StructBlock): text = blocks.TextBlock() buttons = blocks.ListBlock(ButtonBlock()) mainbutton = ButtonBlock() graphql_fields = [ GraphQLString("text"), GraphQLImage("image"), GraphQLStreamfield("buttons"), GraphQLStreamfield( "mainbutton", is_list=False ), # this is a direct StructBlock, not a list of sub-blocks ]
class GatsbyImageRendition(AbstractRendition): image = models.ForeignKey( GatsbyImage, on_delete=models.CASCADE, related_name="renditions" ) class Meta(AbstractRendition.Meta): abstract = True unique_together = ("image", "filter_spec", "focal_point_key") graphql_fields = ( GraphQLString("id"), GraphQLString("file"), GraphQLString("url"), GraphQLString("width"), GraphQLString("height"), GraphQLImage("image"), )
class CustomImageRendition(AbstractRendition): image = models.ForeignKey("CustomImage", related_name="renditions", on_delete=models.CASCADE) class Meta: unique_together = (("image", "filter_spec", "focal_point_key"), ) def custom_rendition_property(self): return "Rendition Model!" graphql_fields = ( GraphQLString("custom_rendition_property"), GraphQLString("id"), GraphQLString("url"), GraphQLString("width"), GraphQLString("height"), GraphQLImage("image"), GraphQLString("file"), )
class PersonPage(BasePage): template = 'patterns/pages/people/person_page.html' subpage_types = [] parent_page_types = ['people.PersonIndex'] first_name = models.CharField(max_length=255) last_name = models.CharField(max_length=255) photo = models.ForeignKey('images.CustomImage', null=True, blank=True, related_name='+', on_delete=models.SET_NULL) job_title = models.CharField(max_length=255) introduction = models.TextField(blank=True) biography = StreamField(StoryBlock(), blank=True) email = models.EmailField(blank=True) content_panels = BasePage.content_panels + [ MultiFieldPanel([ FieldPanel('first_name'), FieldPanel('last_name'), ], heading="Name"), ImageChooserPanel('photo'), FieldPanel('job_title'), InlinePanel('social_media_profile', label='Social accounts'), MultiFieldPanel([ FieldPanel('email'), ], heading='Contact information'), FieldPanel('introduction'), StreamFieldPanel('biography') ] graphql_fields = [ GraphQLString("name"), GraphQLString("job_title"), GraphQLString("introduction"), GraphQLImage("photo"), GraphQLStreamfield("biography"), ]
class BlogPage(HeadlessPreviewMixin, Page): date = models.DateField("Post date") advert = models.ForeignKey( "home.Advert", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) hero_image = models.ForeignKey( "images.CustomImage", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) book_file = models.ForeignKey( "wagtaildocs.Document", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) featured_media = models.ForeignKey( "wagtailmedia.Media", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) author = models.ForeignKey(AuthorPage, null=True, blank=True, on_delete=models.SET_NULL, related_name="+") body = StreamField(StreamFieldBlock()) tags = ClusterTaggableManager(through=BlogPageTag, blank=True) content_panels = Page.content_panels + [ FieldPanel("date"), ImageChooserPanel("hero_image"), StreamFieldPanel("body"), FieldPanel("tags"), InlinePanel("related_links", label="Related links"), InlinePanel("authors", label="Authors"), FieldPanel("author"), SnippetChooserPanel("advert"), DocumentChooserPanel("book_file"), MediaChooserPanel("featured_media"), ] @property def copy(self): return self def paginated_authors(self, info, **kwargs): return resolve_paginated_queryset(self.authors, info, **kwargs) graphql_fields = [ GraphQLString("date", required=True), GraphQLStreamfield("body"), GraphQLTag("tags"), GraphQLCollection( GraphQLForeignKey, "related_links", "home.blogpagerelatedlink", required=True, item_required=True, ), GraphQLCollection(GraphQLString, "related_urls", source="related_links.url"), GraphQLCollection(GraphQLString, "authors", source="authors.person.name"), GraphQLCollection( GraphQLForeignKey, "paginated_authors", "home.Author", is_paginated_queryset=True, ), GraphQLSnippet("advert", "home.Advert"), GraphQLImage("hero_image"), GraphQLDocument("book_file"), GraphQLMedia("featured_media"), GraphQLForeignKey("copy", "home.BlogPage"), GraphQLPage("author"), ]
class NewsPage(BasePage): template = 'patterns/pages/news/news_page.html' subpage_types = [] parent_page_types = ['NewsIndex'] summary = models.TextField( max_length=280, null=True, blank=True, ) featured_image = models.ForeignKey('images.CustomImage', null=True, blank=True, related_name='+', on_delete=models.SET_NULL) featured_image_caption = models.CharField( blank=True, max_length=250, ) body = RichTextField(blank=True, features=['bold', 'italic', 'link']) tags = ClusterTaggableManager(through=NewsPageTag, blank=True) categories = ParentalManyToManyField('news.NewsPageCategory', blank=True) publication_date = models.DateTimeField( null=True, blank=True, help_text="Use this field to override the date that the " "news item appears to have been published.") search_fields = BasePage.search_fields + [ index.SearchField('summary'), index.SearchField('body') ] content_panels = BasePage.content_panels + [ FieldPanel('summary'), FieldPanel('body', classname="full"), FieldPanel('categories', widget=forms.CheckboxSelectMultiple), FieldPanel('tags'), MultiFieldPanel( [ ImageChooserPanel('featured_image'), FieldPanel('featured_image_caption'), ], heading="Featured Image", ), FieldPanel('publication_date'), ] # Export fields over REST API api_fields = [ APIField('summary'), APIField('body'), APIField('featured_image', serializer=ImageRenditionField('fill-1920x1080')), APIField('featured_image_caption'), ] graphql_fields = [ GraphQLString("summary"), GraphQLString("body"), GraphQLImage("featured_image"), GraphQLString("featured_image_caption"), ] class Meta: verbose_name = "News" @property def display_date(self): if self.publication_date: return self.publication_date else: return self.first_published_at
class CalloutBlock(blocks.StructBlock): text = blocks.RichTextBlock() image = ImageChooserBlock() graphql_fields = [GraphQLString("text"), GraphQLImage("image")]
class BlogPage(HeadlessPreviewMixin, Page): date = models.DateField("Post date") advert = models.ForeignKey( "home.Advert", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) cover = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) book_file = models.ForeignKey( "wagtaildocs.Document", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) featured_media = models.ForeignKey( "wagtailmedia.Media", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) author = models.ForeignKey(AuthorPage, null=True, blank=True, on_delete=models.SET_NULL, related_name="+") body = StreamField(StreamFieldBlock()) content_panels = Page.content_panels + [ FieldPanel("date"), ImageChooserPanel("cover"), StreamFieldPanel("body"), InlinePanel("related_links", label="Related links"), InlinePanel("authors", label="Authors"), FieldPanel("author"), SnippetChooserPanel("advert"), DocumentChooserPanel("book_file"), MediaChooserPanel("featured_media"), ] @property def copy(self): return self graphql_fields = [ GraphQLString("heading"), GraphQLString("date", required=True), GraphQLStreamfield("body"), GraphQLCollection(GraphQLForeignKey, "related_links", "home.blogpagerelatedlink", required=True, item_required=True), GraphQLCollection(GraphQLString, "related_urls", source="related_links.url"), GraphQLCollection(GraphQLString, "authors", source="authors.person.name"), GraphQLSnippet("advert", "home.Advert"), GraphQLImage("cover"), GraphQLDocument("book_file"), GraphQLMedia("featured_media"), GraphQLForeignKey("copy", "home.BlogPage"), GraphQLPage("author"), ]
class ArticlePage(BasePage): template = 'patterns/pages/articles/article_page.html' subpage_types = [] parent_page_types = ['ArticleIndex'] introduction = models.TextField( blank=True, max_length=165, ) featured_image = models.ForeignKey('images.CustomImage', null=True, blank=True, related_name='+', on_delete=models.SET_NULL) featured_image_caption = models.CharField( blank=True, max_length=250, ) body = StreamField(StoryBlock()) license = models.ForeignKey('utils.LicenseSnippet', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') tags = ClusterTaggableManager(through=ArticlePageTag, blank=True) categories = ParentalManyToManyField('articles.ArticlePageCategory', blank=True) # It's datetime for easy comparison with first_published_at publication_date = models.DateTimeField( null=True, blank=True, help_text="Use this field to override the date that the " "articles item appears to have been published.") search_fields = BasePage.search_fields + [ index.SearchField('introduction'), index.SearchField('body') ] content_panels = BasePage.content_panels + [ FieldPanel('introduction'), MultiFieldPanel( [ ImageChooserPanel('featured_image'), FieldPanel('featured_image_caption'), ], heading="Featured Image", ), StreamFieldPanel('body'), InlinePanel('authors', label="Authors"), SnippetChooserPanel('license'), FieldPanel('tags'), FieldPanel('categories', widget=forms.CheckboxSelectMultiple), FieldPanel('publication_date'), # TODO: comment related_pages back in if we have time with the front-end work for articles # InlinePanel('related_pages', label="Related pages"), ] # Export fields over REST API api_fields = [ APIField('introduction'), APIField('body'), APIField('authors'), APIField('tags'), APIField('categories'), APIField('featured_image', serializer=ImageRenditionField('fill-1920x1080')), APIField('featured_image_caption'), ] # Export fields to GraphQL graphql_fields = [ GraphQLString("heading"), GraphQLString("publication_date"), GraphQLStreamfield("body"), GraphQLString("categories"), GraphQLImage("featured_image"), GraphQLString("featured_image_caption") ] class Meta: verbose_name = "Article" @property def display_date(self): if self.publication_date: return self.publication_date else: return self.first_published_at
class CarouselBlock(blocks.StreamBlock): text = blocks.CharBlock(classname="full title") image = ImageChooserBlock() graphql_fields = [GraphQLString("text"), GraphQLImage("image")]
class EventPage(BasePage): template = 'patterns/pages/events/event_page.html' subpage_types = [] parent_page_types = ['EventIndex'] summary = models.TextField( max_length=280, ) featured_image = models.ForeignKey( 'images.CustomImage', null=True, blank=True, related_name='+', on_delete=models.SET_NULL ) featured_image_caption = models.CharField( blank=True, max_length=250, ) body = StreamField(StoryBlock()) # Event time start_date = models.DateField() start_time = models.TimeField( blank=True, null=True ) end_date = models.DateField( blank=True, null=True ) end_time = models.TimeField( blank=True, null=True ) # URLs for more information information_url = models.URLField("Mer informasjon", blank=True) tickets_url = models.URLField("Påmelding", blank=True) program_url = models.URLField("Program", blank=True) streaming_url = models.URLField("Direktestrømming", blank=True) # Location location_name = models.CharField( "Sted", max_length=250, blank=True, ) # Address street_address = models.CharField( "Gateadresse", max_length=512, blank=True ) postal_code = models.CharField( "Postnummer", max_length=12, blank=True ) city = models.CharField( "Poststed", max_length=255, blank=True ) country = models.CharField( "Land", max_length=128, blank=True ) # Tags and categories tags = ClusterTaggableManager(through=EventPageTag, blank=True) categories = ParentalManyToManyField('events.EventPageCategory', blank=True) # Publication date for publishing events at a later time publication_date = models.DateTimeField( null=True, blank=True, help_text="Use this field to set custom publish time for event." ) search_fields = BasePage.search_fields + [ index.SearchField('summary'), index.SearchField('body'), index.SearchField('city'), index.SearchField('location_name'), ] content_panels = BasePage.content_panels + [ FieldPanel('summary'), MultiFieldPanel( [ ImageChooserPanel('featured_image'), FieldPanel('featured_image_caption'), ], heading="Featured Image", ), StreamFieldPanel('body'), MultiFieldPanel( [ FieldPanel('start_date'), FieldPanel('start_time'), FieldPanel('end_date'), FieldPanel('end_time') ], heading="Tidspunkt", ), FieldPanel('categories', widget=forms.CheckboxSelectMultiple), FieldPanel('tags'), MultiFieldPanel( [ FieldPanel('information_url'), FieldPanel('tickets_url'), FieldPanel('program_url'), FieldPanel('streaming_url') ], heading="Mer informasjon", ), MultiFieldPanel( [ FieldPanel('location_name'), FieldPanel('street_address'), FieldPanel('postal_code'), FieldPanel('city'), FieldPanel('country'), ], heading="Sted for arrangentet", ), ] promote_panels = [ FieldPanel('publication_date'), ] + BasePage.promote_panels # Export fields over REST API api_fields = [ APIField('summary'), APIField('body'), APIField('featured_image', serializer=ImageRenditionField('fill-1920x1080')), APIField('featured_image_caption'), APIField('event_starts'), APIField('event_ends'), ] graphql_fields = [ GraphQLString("summary"), GraphQLString("body"), GraphQLImage("featured_image", serializer=ImageRenditionField('fill-1920x1080')), GraphQLString("featured_image_caption"), GraphQLString('event_starts'), GraphQLString('event_ends'), ] class Meta: verbose_name = "Events" @property def event_starts(self): if self.start_time: return datetime.combine(self.start_date, self.start_time) else: return self.start_date @property def event_ends(self): if self.end_date: if self.end_time: return datetime.combine(self.end_date, self.end_time) else: return self.end_date else: return self.start_date @property def location(self): infos = [] location_info = (self.location_name, self.street_address, self.postal_code + ' ' + self.city, self.country) for info in location_info: if info.strip(): infos.append(info) return (', ').join(infos)