class Facet(index.Indexed, ClusterableModel): facet_type = models.ForeignKey(FacetType, blank=True, null=True, on_delete=models.CASCADE) title = models.CharField(max_length=64) api_fields = [APIField('facet_type'), APIField('title')] panels = [FieldPanel('facet_type'), FieldPanel('title', 'full')] search_fields = [ index.RelatedFields('facet_type', [index.SearchField('title')]), index.SearchField('title') ] objects = FacetManager() class Meta: ordering = ['title'] unique_together = [['facet_type', 'title']] def __str__(self): return '{}: {}'.format(self.facet_type, self.title) def natural_key(self): return self.facet_type.natural_key() + (self.title, )
class BlogPage(Page): published_date = models.DateField("Post date") intro = models.CharField(max_length=250) body = RichTextField(blank=True) search_fields = Page.search_fields + [ index.SearchField('intro'), index.SearchField('body'), ] content_panels = Page.content_panels + [ FieldPanel('published_date'), FieldPanel('intro'), FieldPanel('body', classname="full"), ] # Export fields over the API api_fields = [ APIField('published_date'), # Date in ISO8601 format (the default) APIField( 'published_date_display', serializer=DateField(format='%A $d %B %Y', source='published_date') ), # A separate published_date_display field with a different format APIField('body'), APIField( 'authors' ), # This will nest the relevant BlogPageAuthor objects in the API response ]
class NewsPage(HeadlessPreviewMixin, Page): intro = models.CharField(max_length=250) body = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ]) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL ) content_panels = Page.content_panels + [ FieldPanel('intro'), ImageChooserPanel('image'), StreamFieldPanel('body'), ] api_fields = [ APIField('intro'), APIField('body'), APIField('image_thumbnail', serializer=ImageRenditionField('fill-300x300', source='image')), ]
class MoviesIndexPage(Page): """Movies index page""" template = "movie/movies_index.html" sub_title = models.CharField(blank=False, null=False, max_length=255) hero = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) api_fields = [ APIField('sub_title'), APIField('hero', serializer=ImageRenditionField('fill-1920x780')), ] content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('sub_title'), ImageChooserPanel('hero'), ], heading="Header") ] subpage_types = ['movie.MoviePage'] def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["movies"] = MoviePage.objects.live().public() return context def __str__(self): return self.title
class SubjectBooks(models.Model): subject = models.ForeignKey(Subject, on_delete=models.SET_NULL, null=True, related_name='subjects_subject') def get_subject_name(self): return self.subject.name subject_name = property(get_subject_name) def get_subject_page_content(self): return self.subject.page_content subject_page_content = property(get_subject_page_content) def get_subject_page_title(self): return self.subject.seo_title subject_seo_title = property(get_subject_page_title) def get_subject_meta(self): return self.subject.search_description subject_search_description = property(get_subject_meta) api_fields = [ APIField('subject_name'), APIField('subject_page_content'), APIField('subject_search_description') ]
class AboutPage(Page): parent_page_types = [SinglePage] intro = models.CharField(max_length=50) body = models.CharField(max_length=500) image = models.ForeignKey('wagtailimages.Image', on_delete=models.DO_NOTHING, related_name='about_me_main_image', default="", null=True, blank=True) search_fields = Page.search_fields + [ index.SearchField('intro'), ] api_fields = [ APIField('intro'), APIField('body'), APIField('about_me_service'), APIField('about_me_finish_projects'), ] content_panels = Page.content_panels + [ FieldPanel('intro'), FieldPanel('body'), FieldPanel('image'), InlinePanel('about_me_service', heading="Service"), InlinePanel('about_me_finish_projects', heading="Finished projects"), ]
class StandardPage(Page): """ A generic content page. On this demo site we use it for an about page but it could be used for any type of page content that only needs a title, image, introduction and body field """ introduction = models.TextField(help_text='Text to describe the page', blank=True) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', help_text= 'Landscape mode only; horizontal width between 1000px and 3000px.') body = StreamField(BaseStreamBlock(), verbose_name="Page body", blank=True) content_panels = Page.content_panels + [ FieldPanel('introduction', classname="full"), StreamFieldPanel('body'), ImageChooserPanel('image'), ] api_fields = [ APIField('introduction'), APIField('body'), APIField('image'), ]
class BlogAuthorOrderables(Orderable): """ To select authors from Snippet """ page = ParentalKey("blog.BlogDetailPage",related_name="blog_authors") author = models.ForeignKey( "blog.BlogAuthor", on_delete= models.CASCADE, ) panels =[ SnippetChooserPanel("author") ] @property def author_name(self): return self.author.name @property def author_website(self): return self.author.website @property def author_image(self): return self.author.image api_fields = [ APIField("author_name"), APIField("author_website"), APIField("author_image",serializer=ImageSerializedField()), ]
class Experts(models.Model): name = models.CharField(max_length=255) email = models.EmailField(blank=True, null=True) title = models.CharField(max_length=255) bio = models.TextField() image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', ) def get_expert_image(self): return build_image_url(self.image) expert_image = property(get_expert_image) api_fields = [ APIField('name'), APIField('email'), APIField('title'), APIField('bio'), APIField('expert_image') ] panels = [ FieldPanel('name'), FieldPanel('email'), FieldPanel('title'), FieldPanel('bio'), ImageChooserPanel('image'), ]
class VideoBlogPage(BlogDetailPage): """A subclassed blog post page for articles""" youtube_video_id = models.CharField(max_length=30) content_panels = Page.content_panels + [ FieldPanel("custom_title"), FieldPanel("youtube_video_id"), StreamFieldPanel("content"), ] banner_panels = [ FieldPanel("tags"), ImageChooserPanel("banner_image"), InlinePanel("blog_authors", label="Author", max_num=1), FieldPanel( "categories", widget=forms.CheckboxSelectMultiple, ), ] api_fields = [ APIField("blog_authors"), APIField("content"), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Content"), ObjectList(banner_panels, heading="Banner"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings"), ])
class BlogAuthorsOrderable(Orderable): """us to select one or more blog authors from Snippet""" page = ParentalKey("BlogDetailPage", related_name="blog_authors") author = models.ForeignKey("BlogAuthor", on_delete=models.CASCADE) panels = [SnippetChooserPanel("author")] @property def author_name(self): return self.author.name @property def author_website(self): return self.author.website @property def author_image(self): return self.author.image api_fields = [ APIField("author_name"), APIField("author_website"), # This is using a custom django rest framework serializer APIField("author_image", serializer=ImageSerializedField()), # The below APIField is using a Wagtail-built DRF Serializer that supports # custom image rendition sizes APIField("image", serializer=ImageRenditionField('fill-200x250', source="author_image")), ]
class ArticleBlogPage(BlogDetailPage): """A subclassed blog post page for articles""" subtitle = models.CharField(max_length=100, blank=True, null=True) 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') content_panels = Page.content_panels + [ FieldPanel("custom_title"), FieldPanel("subtitle"), StreamFieldPanel("content"), ] banner_panels = [ FieldPanel("tags"), ImageChooserPanel("banner_image"), ImageChooserPanel('intro_image'), InlinePanel("blog_authors", label="Author", max_num=1), FieldPanel("categories", widget=forms.CheckboxSelectMultiple), ] api_fields = [ APIField("blog_authors"), APIField("content"), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Content"), ObjectList(banner_panels, heading="Banner"), ObjectList(Page.promote_panels, heading="Promote"), ObjectList(Page.settings_panels, heading="Settings"), ])
class RelatedDocOrderable(Orderable): page = ParentalKey("legislation.LawPage", related_name='related_docs') related_doc = models.ForeignKey("base.CustomDocument", null=True, blank=True, on_delete=models.SET_NULL, related_name='+') @property def title(self): return self.related_doc.title @property def filename(self): return self.related_doc.filename @property def file_size(self): return self.related_doc.get_file_size() @property def file_extension(self): return self.related_doc.file_extension panels = [DocumentChooserPanel('related_doc')] api_fields = [ APIField('title'), APIField('related_doc'), APIField('filename'), APIField('file_size'), APIField('file_extension') ]
class LegislationIndexPage(Page): parent_page_types = ['home.HomePage'] subpage_types = ['legislation.LawsSectionPage'] max_count = 1 banner = models.ForeignKey('wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True) @property def sections(self): return [{ 'id': child.id, 'title': child.title, 'url': child.url } for child in self.get_children()] content_panels = Page.content_panels + [ ImageChooserPanel('banner', heading='Иллюстрация') ] api_fields = [ APIField('banner', serializer=ImageRenditionField(BANNER_SIZE)), APIField('sections') ] def get_sitemap_urls(self, request): return [] class Meta: verbose_name = 'Страница Законодательства'
class Actor(Page): """Актеры и режиссеры""" age = models.PositiveSmallIntegerField("Возраст", default=0) description = models.TextField("Описание") image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') api_fields = [ APIField('title'), APIField('description'), ] content_panels = Page.content_panels + [ FieldPanel('age'), ImageChooserPanel('image'), FieldPanel('description'), ] def __str__(self): return self.title def get_absolute_url(self): return reverse('actor_detail', kwargs={"slug": self.title}) class Meta: verbose_name = "Актеры и режиссеры" verbose_name_plural = "Актеры и режиссеры" db_table = "'catalog'.'actor'"
class BlogAuthorOrderable(Orderable): """ This allows us to select one or more authors to a post """ page = ParentalKey('blog.BlogDetailPage', related_name='blog_authors') author = models.ForeignKey( 'blog.BlogAuthor', on_delete=models.CASCADE, ) panels = [ SnippetChooserPanel('author'), ] @property def author_name(self): return self.author.name @property def author_website(self): return self.author.website @property def author_image(self): return self.author.image api_fields = [ APIField('author_name'), APIField('author_website'), #APIField('author_image', serializer=ImageSerializedField()), APIField('image', serializer=ImageRenditionField('fill-200x250', source='author_image')), ]
class ContentPage(Page): pageBackDrop = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) body = StreamField(MyStreamBlock([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.TextBlock()), ('image', MyImageChooserBlock()), ], blank=True, null=True)) content_panels = Page.content_panels + [ ImageChooserPanel('pageBackDrop'), StreamFieldPanel('body'), ] api_fields = [ APIField('pageBackDrop'), APIField('body'), ]
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 NavigationSettings(BaseSetting, ClusterableModel): primary_navigation = StreamField([("link", PrimaryNavLink())], blank=True, help_text="Main site navigation") quick_links = StreamField([("link", QuickLinkBlock())], blank=True) footer_navigation = StreamField( [("link", LinkBlock())], blank=True, help_text="Multiple columns of footer links with optional header.", ) footer_links = StreamField( [("link", LinkBlock())], blank=True, help_text="Single list of elements at the base of the page.", ) panels = [ StreamFieldPanel("quick_links"), StreamFieldPanel("primary_navigation"), StreamFieldPanel("footer_navigation"), StreamFieldPanel("footer_links"), ] api_fields = [ APIField("quick_links"), APIField("primary_navigation"), APIField("footer_navigation"), APIField("footer_links"), ]
class HomePage(Page, models.Model): # db fields h_one = models.CharField(max_length=250, default="H1") h_one_span = models.CharField(max_length=250, default="H1 Span") content = models.TextField(blank=True, null=True) # Search index configuration search_fields = Page.search_fields + [ index.SearchField('h_one'), index.SearchField('h_one_span'), index.FilterField('content'), ] # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('h_one'), FieldPanel('h_one_span'), FieldPanel('content'), ] # API configuration api_fields = [ APIField('h_one'), APIField('h_one_span'), APIField('content'), ]
class FormPage(AbstractEmailForm): image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') body = StreamField(BaseStreamBlock()) thank_you_text = RichTextField(blank=True) # Note how we include the FormField object via an InlinePanel using the # related_name value content_panels = AbstractEmailForm.content_panels + [ ImageChooserPanel('image'), StreamFieldPanel('body'), InlinePanel('form_fields', label="Form fields"), FieldPanel('thank_you_text', classname="full"), MultiFieldPanel([ FieldRowPanel([ FieldPanel('from_address', classname="col6"), FieldPanel('to_address', classname="col6"), ]), FieldPanel('subject'), ], "Email"), ] api_fields = [ APIField('image'), APIField('body'), ]
class WorkPage(Page): """Each individual blog post goes here""" job_title = models.CharField(max_length=100, blank=False, null=True) work_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=False, on_delete=models.SET_NULL, related_name="+", ) work_skills = ClusterTaggableManager(through=WorkSkill, blank=True) api_fields = [ APIField("job_title"), APIField( "work_image", serializer=ImageRenditionField("max-500x500"), ), APIField("work_skills"), ] content_panels = Page.content_panels + [ FieldPanel("job_title"), ImageChooserPanel("work_image"), FieldPanel("work_skills"), ] pass
class HomePageCarousel(Orderable): """Add between 1 and 5 images.""" page = ParentalKey("home.HomePage", related_name="carousel_images") carousel_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) title = models.CharField(max_length=40, null=True, blank=True) subtitle = models.CharField(max_length=100, null=True, blank=True) text_orient = models.CharField( choices=(("left", "Left"), ("right", "Right"), ("center", "Center")), max_length=20, null=True, blank=True, ) api_fields = [ APIField("title"), APIField("subtitle"), APIField("text_orient"), APIField("carousel_image"), ] panels = [ FieldPanel("title"), FieldPanel("subtitle"), FieldPanel("text_orient"), ImageChooserPanel("carousel_image"), ]
class BlogPageGalleryImage(Orderable): page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='gallery_images') image = models.ForeignKey('wagtailimages.Image', on_delete=models.CASCADE, related_name='+') caption = models.CharField(blank=True, max_length=250) api_fields = [ APIField('image'), APIField('caption'), APIField('page'), APIField('image_thumbnail', serializer=ImageRenditionField('fill-100x100', source='image')), APIField('image_medium', serializer=ImageRenditionField('fill-300x300', source='image')) ] panels = [ ImageChooserPanel('image'), FieldPanel('caption'), ]
class WelcomePage(Page): subpage_types = [] parent_page_types = [SinglePage] first_line = models.CharField(max_length=250) second_line = models.CharField(max_length=250) third_line = models.CharField(max_length=250) button_name = models.CharField(max_length=250) image = models.ForeignKey( 'wagtailimages.Image', on_delete=models.DO_NOTHING, related_name='welcome_main_image', default="", null=True, blank=True ) api_fields = [ APIField('first_line'), APIField('second_line'), APIField('third_line'), APIField('button_name'), APIField('image'), ] content_panels = Page.content_panels + [ FieldPanel('first_line'), FieldPanel('second_line'), FieldPanel('third_line'), FieldPanel('button_name'), FieldPanel('image'), ]
class SeriesEpisode(Orderable): """Episode class""" page = ParentalKey("series.SeriesPage", on_delete=models.CASCADE, related_name="episodes") video = models.ForeignKey("video.Video", on_delete=models.CASCADE, related_name="+") is_new = models.BooleanField(blank=True, null=False, default=False, verbose_name="New episode") api_fields = [ APIField('video', serializer=VideoSerializer('fill-512x288')), APIField('is_new'), ] panels = [ VideoChooserPanel('video'), FieldPanel('is_new'), ] def __str__(self): return self.series.title + ": " + self.video.title
class BlogPage(BasePage): template = "blog/blog_page.jinja" parent_page_types = ['wesgarlockblog.BlogIndexPage'] date = models.DateField("Post date") intro = models.CharField(max_length=1000, blank=True, null=True) body = RichTextField(blank=True) tags = ClusterTaggableManager(through=BlogPageTag, blank=True) search_fields = BasePage.search_fields + [ index.SearchField('tags'), ] content_panels = BasePage.content_panels + [ MultiFieldPanel([ FieldPanel('date'), FieldPanel('tags'), FieldPanel('intro'), ], heading="Blog information"), FieldPanel('body', classname='full'), ] api_fields = BasePage.api_fields + [ APIField("date"), APIField("tags"), APIField("intro"), APIField("body") ] serializer = "wesgarlock.blog.serializers:BlogPageSerializer" class Meta: verbose_name = _('Blog Page') verbose_name_plural = _('Blog Pages')
class SeriesIndexPage(Page): """Series index page""" template = "series/series_index.html" sub_title = models.CharField(blank=False, null=False, max_length=255) hero = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) api_fields = [ APIField('sub_title'), APIField('hero', serializer=ImageRenditionField('fill-1920x780')), ] content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('sub_title'), ImageChooserPanel('hero'), ], heading="Header"), ] parent_page_types = ['home.HomePage'] subpage_types = ['series.SeriesIndexPage', 'series.SeriesPage'] def get_context(self, request, *args, **kwargs): """Adding custom stuff to our context.""" context = super().get_context(request, *args, **kwargs) context["series"] = SeriesPage.objects.live().public() return context
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 ScenePage(Page): prev = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', help_text='预览', verbose_name="预览") img = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', help_text='图案', verbose_name="图案") content_panels = Page.content_panels + [ ImageChooserPanel('prev'), ImageChooserPanel('img'), ] api_fields = [ APIField('prev'), APIField('img'), ]