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, )
Exemple #2
0
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
    ]
Exemple #3
0
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')),
    ]
Exemple #4
0
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
Exemple #5
0
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')
    ]
Exemple #6
0
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"),
    ]
Exemple #7
0
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'),
    ]
Exemple #8
0
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()),
    ]
Exemple #9
0
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'),
    ]
Exemple #10
0
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"),
    ])
Exemple #11
0
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")),
    ]
Exemple #12
0
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"),
    ])
Exemple #13
0
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')
    ]
Exemple #14
0
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 = 'Страница Законодательства'
Exemple #15
0
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'"
Exemple #16
0
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')),
    ]
Exemple #17
0
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)
Exemple #19
0
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"),
    ]
Exemple #20
0
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'),
    ]
Exemple #21
0
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'),
    ]
Exemple #22
0
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
Exemple #23
0
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"),
    ]
Exemple #24
0
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'),
    ]
Exemple #25
0
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
Exemple #27
0
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
Exemple #29
0
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'),
    ]