class HomePage(Page): ''' home page model''' templates = "home/home_page.html" max_count = 1 banner_title = models.CharField(max_length=100, blank=False, null=True) banner_subtitle = models.CharField(max_length=200, blank=False, null=True) vision_and_mission = models.TextField(null=True, blank=True, default="UMA Vision and Mission") logo_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=False, on_delete=models.SET_NULL, related_name="+", ) content = StreamField( [ ("cards", blocks.CardBlock()), ], null=True, blank=True, ) workshop_and_events = StreamField( [ ("cards", blocks.CardBlock()), ], null=True, blank=True, ) important_links = RichTextField(features=['link'], null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel("banner_title"), FieldPanel("banner_subtitle"), ImageChooserPanel("logo_image"), MultiFieldPanel( [ InlinePanel( "carousel_images", max_num=3, min_num=1, label="Image"), ], heading="Carousel Panel", ), FieldPanel("vision_and_mission"), MultiFieldPanel([ StreamFieldPanel("content"), ], heading="Participating Institutes"), FieldPanel("important_links"), MultiFieldPanel([ StreamFieldPanel("workshop_and_events"), ], heading="Workshop and events"), ]
class BlogDetailPage(Page): custom_title = models.CharField( max_length=100, blank = False, null = False, help_text = 'Overwrites the default title' ) blog_image = models.ForeignKey( "wagtailimages.Image", blank = True, null = True, related_name="+", on_delete = models.SET_NULL, ) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("cards", blocks.CardBlock()) ], null = True, blank = True ) content_panels = Page.content_panels + [ FieldPanel("custom_title"), ImageChooserPanel("blog_image"), StreamFieldPanel("content") ]
class BlogDetailPage(Page): """Detail blog articles""" custom_title = models.CharField( max_length=100, blank=False, null=False, help_text="Custom title from blog detail page") blog_image = models.ForeignKey("wagtailimages.Image", blank=False, null=True, help_text="Blog article image", related_name="+", on_delete=models.SET_NULL) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True, ) content_panels = Page.content_panels + [ FieldPanel("custom_title"), ImageChooserPanel("blog_image"), StreamFieldPanel("content"), ]
class ProjectDetailPage(Page): """Project Detail Page""" custom_title = models.CharField( max_length=100, blank=False, null=False, help_text='Overwrites the default content.') project_image = models.ForeignKey("wagtailimages.Image", blank=False, null=True, related_name="+", on_delete=models.SET_NULL) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichTextBlock()), ("cards", blocks.CardBlock()), ], null=True, blank=True, ) categories = ParentalManyToManyField("project.ProjectCategory", blank=True) content_panels = Page.content_panels + [ FieldPanel("custom_title"), ImageChooserPanel("project_image"), MultiFieldPanel( [FieldPanel("categories", widget=forms.CheckboxSelectMultiple)], heading="Categories"), StreamFieldPanel("content"), ]
class ContactPage(AbstractEmailForm): template = "contact/contact_page.html" # This is the default path. # If ignored, Wagtail adds _landing.html to your template name landing_page_template = "contact/contact_page_landing.html" intro = RichTextField(blank=True) thank_you_text = RichTextField(blank=True) content_panels = AbstractEmailForm.content_panels + [ StreamFieldPanel("content"), FieldPanel('intro'), InlinePanel('form_fields', label='Form Fields'), FieldPanel('thank_you_text'), MultiFieldPanel([ FieldRowPanel([ FieldPanel('from_address', classname="col6"), FieldPanel('to_address', classname="col6"), ]), FieldPanel("subject"), ], heading="Email Settings"), ] content = StreamField( [ ("cards", blocks.CardBlock()), ], null=True, blank=True, )
class HomePage(Page): templates = "home/hompage_page.html" carousel_images = StreamField(blocks.CarouselBlock(max_num=3, required=False), blank=True, null=True) content = StreamField( [ ('team', blocks.TeamCards()), ('image', blocks.ImageBlock()), ("jumbotron", blocks.ActionAreaBlock()), ("title_and_text", blocks.TitleAndTextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True, ) content_panels = Page.content_panels + [ StreamFieldPanel("carousel_images"), StreamFieldPanel("content"), ] class Meta: verbose_name = "Home Page" verbose_name_plural = "Home Pages"
class BlogDetailPage(Page): """Blog detail page""" custom_title = models.CharField(max_length=100, blank=False, null=False, help_text='Overwrites the default title') blog_image = models.ForeignKey('wagtailimages.Image', blank=False, null=True, related_name='+', on_delete=models.SET_NULL) content = StreamField([ ('title_and_text', blocks.TitleAndTextBlock()), ('full_richtext', blocks.RichtextBlock()), ('simple_richtext', blocks.SimpleRichtextBlock()), ('cards', blocks.CardBlock()), ('cta', blocks.CTABlock()), ], null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel('custom_title'), ImageChooserPanel('blog_image'), StreamFieldPanel('content'), ]
class FlexPage(Page): # @remember: # This page generates the blocks/streamfields on the your flex_page.html. # Copy/Paste this whole class to make other pages flexibe, # Change the template. template = 'flex/flex_page.html' # @remember: # This is the content being rendered on the flex_page.html content = StreamField( [ ('title_and_text', blocks.TitleAndTextBlock()), ('full_richtext', blocks.RichTextBlock()), ('simple_richtext', blocks.SimpleRichTextBlock()), ('service_cards', blocks.CardBlock()), ], null=True, blank=True ) subtitle = models.CharField(max_length=150, null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel('subtitle'), StreamFieldPanel('content'), ] class Meta: verbose_name = 'Flex Page' verbose_name_plural = 'Flex Pages'
class FlexPage(Page): """flexbile page class""" template = "flex/flex_page.html" parent_page_types = ['flex.FlexPage', 'home.HomePage'] subpage_types = ['flex.FlexPage'] subtitle = models.CharField(max_length=100, null=True, blank=True) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichTextBlock()), ("simple_richtext", blocks.SimpleRichTextBlock()), # ("simple_richtext", blocks.SimpleRichTextBlock(features=["bold", "italic"])), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ("button", blocks.ButtonBlock()), ], null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel("subtitle"), StreamFieldPanel("content"), ] class Meta: # noqa verbose_name = "Flex Page" verbose_name_plural = "Flex Pages"
class BlogPage(Page): date = models.DateField("Post date") banner_image = models.ForeignKey("wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+") intro_image = models.ForeignKey( "wagtailimages.Image", blank=True, null=True, on_delete=models.SET_NULL, help_text='Best size for this image will be 1400x400') intro = models.CharField(max_length=250) body = StreamField( [ ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True, ) content_panels = Page.content_panels + [ FieldPanel('date'), ImageChooserPanel("banner_image"), ImageChooserPanel("intro_image"), FieldPanel('intro'), StreamFieldPanel('body'), ]
class PostPage(Page): """Model for page with a post""" template = 'blog/post_page.html' subpage_types = [] subtitle = models.CharField(max_length=200, null=True, blank=True) image = models.ForeignKey( "wagtailimages.Image", blank=True, null=True, related_name="+", on_delete=models.SET_NULL, ) content = StreamField( [ ("description", blocks.SimpleRichtextBlock()), ("ctablock", blocks.CTABlock()), ("cardblock", blocks.CardBlock()), ], null=True, blank=True, ) categories = ParentalManyToManyField("blog.BlogCategory", blank=True) content_panels = Page.content_panels + [ FieldPanel("subtitle"), MultiFieldPanel([ FieldPanel("categories", widget=forms.CheckboxSelectMultiple), ]), ImageChooserPanel("image"), StreamFieldPanel("content"), ]
class FlexPage(Page): """ Flex page model """ template = "flex/flex.html" # Django models subtitle = models.CharField(max_length=100, null=True, blank=True) # Wagtail models content = StreamField([ ("title_and_text", blocks.TitleAndTextBlock()), ("full_rich_text", blocks.FullRichTextBlock()), ("simple_rich_text", blocks.SimpleRichTextBlock()), ("cards_blocks", blocks.CardBlock()), ], blank=True, null=True) # Add the all of fields to Wagtail panels content_panels = Page.content_panels + [ FieldPanel("subtitle"), StreamFieldPanel("content"), ] class Meta: verbose_name = "Flex page" verbose_name_plural = "Flex pages"
class FlexPage(Page): template = "flex/flex_page.html" #@todo add streamfields content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()) ], null=True, blank=True, ) subtitle = models.CharField(max_length=100, null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel("subtitle"), StreamFieldPanel("content"), ] class Meta: verbose_name = "Flex Page" verbose_name_plural = "Flex Pages"
class BlogIndexPage(Page): """Blog Index Page""" template = "blog/blog_index_page.html" intro = RichTextField(blank=True) content = StreamField( [ ("title_and_text", my_blocks.TitleAndTextBlock()), ("cards", my_blocks.CardBlock()), ('embed', EmbedBlock(icon="media")), ], blank=True, ) subtitle = models.CharField(max_length=100, blank=True) content_panels = Page.content_panels + [ FieldPanel("subtitle"), StreamFieldPanel("content"), ] def get_context(self, request): # Update context to include only published posts, # in reverse chronological order context = super(BlogIndexPage, self).get_context(request) live_blogpages = self.get_children().live() context['blogpages'] = live_blogpages.order_by('-first_published_at') return context
class BlogPage(Page): date = models.DateField("Post Date") intro = models.CharField(max_length = 250) body = RichTextField(blank = True) tags = ClusterTaggableManager(through=BlogTag, blank = True) categories = ParentalManyToManyField('blog.BlogCategory', blank = True) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True, ) search_fields = Page.search_fields + [ index.SearchField('intro'), index.SearchField('body'), ] content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('date'), FieldPanel('tags'), FieldPanel('categories', widget = forms.CheckboxSelectMultiple), ], heading = "Blog Information"), FieldPanel('intro'), StreamFieldPanel("content"), InlinePanel('gallery_images', label = "Gallery images"), ]
class HomeFlexPage(Page): template = 'home/home_page.html' content = StreamField( [ ('title_and_text', blocks.TitleAndTextBlock()), ('full_richtext', blocks.RichTextBlock()), ('simple_richtext', blocks.SimpleRichTextBlock()), ('service_cards', blocks.CardBlock()), ], null=True, blank=True ) subtitle = models.CharField(max_length=150, null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel('subtitle'), StreamFieldPanel('content'), ] class Meta: verbose_name = 'Flexed Home Page' verbose_name_plural = 'Flexed Home Pages'
class FlexPage(Page): parent_page_types = ["home.HomePage", "flex.FlexPage"] body = StreamField( [("title", blocks.TitleBlock()), ("cards", blocks.CardBlock()), ("image_and_text", blocks.ImageAndTextBlock()), ("cta", blocks.CallToActionBlock()), ("testimonial", SnippetChooserBlock( target_model='testimonials.Testimonial', template="streams/testimonial_block.html", )), ("pricing_table", blocks.PricingTableBlock(table_options=NEW_TABLE_OPTIONS, )), ("richtext", wagtail_blocks.RichTextBlock( template="streams/simple_richtext_block.html", )), ("large_image", ImageChooserBlock( help_text='This image will be cropped to 1200px by 775px', template="streams/large_image_block.html"))], null=True, blank=True) content_panels = Page.content_panels + [ StreamFieldPanel("body"), ] class Meta: verbose_name = "Flex (misc) page" verbose_name_plural = "Flex (misc) pages"
class BlogAbout(Page): subpage_types = [] max_count = 1 address = models.CharField(max_length=250, blank=True, null=True) location = models.CharField(max_length=250, blank=True, null=True) content = StreamField([ ("title_and_text", blocks.TitleAndTextBlock()), ("Full_richtext", blocks.RichtextBlock()), ("card_block", blocks.CardBlock()), ], null=True, blank=True) subtitle = models.CharField(max_length=250, blank=True, null=True) content_panels = Page.content_panels + [ FieldPanel('subtitle'), StreamFieldPanel("content"), MultiFieldPanel([ FieldPanel('address'), GeoPanel('location', address_field='address'), ], _('Geo details')), ] @cached_property def point(self): return geosgeometry_str_to_struct(self.location) @property def lat(self): return self.point['y'] @property def lng(self): return self.point['x']
class FlexPage(Page): template = "flex/flex_page.html" banner_title = models.CharField (max_length=100, blank=False, null=True) banner_subtitle = models.CharField (max_length=100, blank=False, null=True) banner_image = models.ForeignKey( "wagtailimages.Image", null = True, blank = False, on_delete = models.SET_NULL, related_name = "+", ) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.FullRichTextBlock()), ("cards", blocks.CardBlock()) ], null= True, blank=True, ) content_panels = Page.content_panels + [ FieldPanel("banner_title"), FieldPanel("banner_subtitle"), ImageChooserPanel("banner_image"), StreamFieldPanel("content"), ] class Meta: verbose_name = "Flex Page" verbose_name_plural = "Flex Pages"
class BlogDetailPage(Page): """Blog detail page.""" template = "blog/blog_detail_page.html" custom_title = models.CharField(max_length=100, blank=False, null=False, help_text="Overwrites the default title.") blog_image = models.ForeignKey("wagtailimages.Image", blank=False, null=True, related_name="+", on_delete=models.SET_NULL) content = StreamField([ ("title_and_text", blocks.TitleAndTextBlock()), ("full_rich_text", blocks.RichTextBlock()), ("simple_richtext", blocks.SimpleRichTextBlock()), ("cards", blocks.CardBlock()), ("call_to_action", blocks.CTABlock()), ], null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel('custom_title'), ImageChooserPanel('blog_image'), StreamFieldPanel("content") ]
class HomePage(Page): parent_page_types = ["wagtailcore.Page"] max_count = 1 standard = StreamField([ ("title_and_text", blocks.TitleAndTextBlock()), ("richtext", blocks.RichtextBlock()), ("simplerichtext", blocks.SimpleRichtextBlock()), ("buttons", blocks.ButtonBlock()), ], null=True, blank=True) sections = StreamField([ ("cards", blocks.CardBlock()), ("products", blocks.ProductCardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True) content_panels = Page.content_panels + [ StreamFieldPanel("standard"), StreamFieldPanel("sections"), ] api_fields = [ APIField("standard"), APIField("sections"), ]
class ContactPage(AbstractEmailForm): template = 'contact/contact_page.html' intro = RichTextField(blank=True) thank_you_title = RichTextField(blank=True) thank_you_text = RichTextField(blank=True) contact_page_panels = StreamField( [ ('service_cards', blocks.CardBlock()), ], null=True, blank=True ) content_panels = AbstractEmailForm.content_panels + [ FieldPanel('intro'), InlinePanel('form_fields', label='Form Fields'), MultiFieldPanel([ FieldPanel('thank_you_title'), FieldPanel('thank_you_text'), ], heading='Thank You Page Text'), MultiFieldPanel([ FieldRowPanel([ FieldPanel('from_address', classname='col6'), FieldPanel('to_address', classname='col6'), ]), FieldPanel('subject'), ], heading='Email Settings'), StreamFieldPanel('contact_page_panels'), ]
class FlexPage(Page): """Flexible page class.""" template = "flex/flex_page.html" content = StreamField([ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichTextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ("button", blocks.ButtonBlock()), ], null=True, blank=True) subtitle = models.CharField(max_length=100, null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel("subtitle"), StreamFieldPanel("content"), ] class Meta: # noqa verbose_name = "Flex Page" verbose_name_plural = "Flex Pages"
class FlexPage(Page): """Flexible page class""" template = 'flex/flex_page.html' content = StreamField([ ("title_and_text", blocks.TitleAndTextBlock()), ("RichText_Tool", blocks.RichtextBlock()), ("Simple_RichText_Tool", blocks.SimpleRichtextBlock()), ("Cards", blocks.CardBlock()), ("Call_to_action", blocks.CTABlock()), ("Button_Url", blocks.ButtonBlock()), ], null=True, blank=True) subtitle = models.CharField(max_length=100, blank=True, null=True) content_panels = Page.content_panels + [ FieldPanel('subtitle'), StreamFieldPanel('content'), ] class Meta: # noqa verbose_name = "Flex Page" verbose_name_plural = "Flex Pages"
class JournalPage(Page): """Journal page class.""" template = "journal/journal_page.html" content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("Raw_HTML", blocks.RawHTMLBlock()), ("cards", blocks.CardBlock()), ], null=True, blank=True, ) subtitle = models.CharField(max_length=100, null=True, blank = True) content_panels = Page.content_panels + [ FieldPanel("subtitle"), StreamFieldPanel("content"), ] class Meta: # noqa verbose_name = "Journal Page" verbose_name_plural = "Journal Pages"
class CommunityPage(Page): body = StreamField([ ("heading", blocks.CharBlock(classname="full title")), ("paragraph", blocks.RichTextBlock()), ("image", ImageChooserBlock()), ("card", wf_blocks.CardBlock()), ("card_row", blocks.ListBlock(wf_blocks.PageCardBlock(label="Page"), template="streams/blocks/card_row.html")), ], null=True) content_panels = Page.content_panels + [ StreamFieldPanel("body"), ] max_count = 1 subpage_types = [ "contact.MeetingIndexPage", "contact.OrganizationIndexPage", "contact.PersonIndexPage", "community.CommunityDirectoryIndexPage", "community.OnlineWorshipIndexPage", ]
class BlogDetailPage(Page): """Parental blog detail page.""" subpage_types = [] parent_page_types = ['blog.BlogListingPage'] tags = ClusterTaggableManager(through=BlogPageTag, blank=True) custom_title = models.CharField( max_length=100, blank=False, null=False, help_text='Overwrites the default title', ) banner_image = models.ForeignKey( "wagtailimages.Image", blank=False, null=True, related_name="+", on_delete=models.SET_NULL, ) categories = ParentalManyToManyField("blog.BlogCategory", blank=True) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichtextBlock()), ("simple_richtext", blocks.SimpleRichtextBlock()), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True, ) content_panels = Page.content_panels + [ FieldPanel("custom_title"), FieldPanel("tags"), ImageChooserPanel("banner_image"), MultiFieldPanel([ InlinePanel("blog_authors", label="Author", min_num=1, max_num=4) ], heading="Author(s)"), MultiFieldPanel( [FieldPanel("categories", widget=forms.CheckboxSelectMultiple)], heading="Categories"), StreamFieldPanel("content"), ] api_fields = [ APIField("blog_authors"), APIField("content"), ] def save(self, *args, **kwargs): """Create a template fragment key. Then delete the key.""" key = make_template_fragment_key("blog_post_preview", [self.id]) cache.delete(key) return super().save(*args, **kwargs)
class NewsPage(Page) : """ News page temaple""" template = "news/news_page.html" # @todo add streamfields content_stream = StreamField( [ ("title_and_text", my_blocks.TitleAndTextBlock()), ("full_richText", my_blocks.RichTextBlock()), ("simple_richText", my_blocks.SimpleRichTextBlock()), ("cards", my_blocks.CardBlock()), ("cta", my_blocks.CtaBlock()), ("button_url",my_blocks.ButtonBlock()), ("char_block", blocks.CharBlock( required=True, help_text='Oh wow this is help text!!', min_length=10, max_length=50, template="streams/char_block.html", )) ], null = True, blank = True ) subtitle = models.CharField(max_length = 100 , null = True , blank = True) content_panels = Page.content_panels + [ FieldPanel("subtitle"), StreamFieldPanel("content_stream") ] class Meta: verbose_name = "News Page" verbose_name_plural = "News Pages"
class BlogDetailPage(Page): """Parental blog detail page.""" parent_page_types = ['blog.BlogListingPage'] subpage_types = [] # author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts", null=True, blank=True) custom_title = models.CharField( max_length=100, blank=False, null=False, help_text='Overwrites the default title', # verbose_name="タイトル" ) banner_image = models.ForeignKey( "wagtailimages.Image", blank=False, null=True, related_name="+", on_delete=models.SET_NULL, ) image_alt = models.CharField( max_length=100, blank=True, null=True, help_text='Add some alt text', ) categories = ParentalManyToManyField("blog.BlogCategory", blank=True, related_name="posts") tags = ClusterTaggableManager(through=BlogPageTag, blank=True) content = StreamField( [ ("title_and_text", blocks.TitleAndTextBlock()), ("full_richtext", blocks.RichTextBlock()), ("simple_richtext", blocks.SimpleRichTextBlock()), # ("simple_richtext", blocks.SimpleRichTextBlock(features=["bold", "italic"])), ("cards", blocks.CardBlock()), ("cta", blocks.CTABlock()), ], null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel("custom_title"), ImageChooserPanel("banner_image"), FieldPanel("image_alt", heading="Image Alt (Option)"), MultiFieldPanel([ InlinePanel("blog_authors", label="Author", min_num=1, max_num=4) ], heading="Author(s)"), FieldPanel("categories", widget=forms.CheckboxSelectMultiple), FieldPanel("tags"), StreamFieldPanel("content"), ]
class BlogDetailPage(Page): """ Parental blog Detail page """ subpage_types = [] parent_page_types = ['blog.BlogListingPage'] tags = ClusterTaggableManager(through=BlogPageTag, blank=True) custom_title = models.CharField( max_length=100, blank=False, null=False, help_text='Add your title', ) banner_image = models.ForeignKey( 'wagtailimages.Image', blank=False, null=True, related_name='+', on_delete=models.SET_NULL, ) categories = ParentalManyToManyField('blog.BlogCategory', blank=True) content = StreamField([ ('title_and_text', blocks.TitleAndTextBlock()), ('full_richtext', blocks.RichTextBlock()), ('cards', blocks.CardBlock()), ('cta', blocks.CTABlock()), ], null=True, blank=True) content_panels = Page.content_panels + [ FieldPanel('custom_title'), FieldPanel("tags"), ImageChooserPanel('banner_image'), StreamFieldPanel('content'), MultiFieldPanel([ InlinePanel('blog_authors', label='Author', min_num=1, max_num=4) ], heading='Authors'), MultiFieldPanel( [FieldPanel('categories', widget=forms.CheckboxSelectMultiple)], heading='Categories'), ] api_fields = [ APIField('blog_authors'), APIField('content'), ] def save(self, *args, **kwargs): key = make_template_fragment_key('blog_post_preview', [self.id]) cache.delete(key) return super().save(*args, **kwargs)