class EventPage(Page): date_from = models.DateField("Start date", null=True) date_to = models.DateField( "End date", null=True, blank=True, help_text="Not required if event is on a single day", ) time_from = models.TimeField("Start time", null=True, blank=True) time_to = models.TimeField("End time", null=True, blank=True) audience = models.CharField(max_length=255, choices=EVENT_AUDIENCE_CHOICES) location = models.CharField(max_length=255) body = RichTextField(blank=True) cost = models.CharField(max_length=255) signup_link = models.URLField(blank=True) feed_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) categories = ParentalManyToManyField(EventCategory, blank=True) search_fields = [ index.SearchField("get_audience_display"), index.SearchField("location"), index.SearchField("body"), index.FilterField("url_path"), ] password_required_template = "tests/event_page_password_required.html" base_form_class = EventPageForm content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("date_from"), FieldPanel("date_to"), FieldPanel("time_from"), FieldPanel("time_to"), FieldPanel("location"), FieldPanel("audience"), FieldPanel("cost"), FieldPanel("signup_link"), InlinePanel("carousel_items", label="Carousel items"), FieldPanel("body", classname="full"), InlinePanel("speakers", label="Speakers", heading="Speaker lineup"), InlinePanel("related_links", label="Related links"), FieldPanel("categories"), # InlinePanel related model uses `pk` not `id` InlinePanel("head_counts", label="Head Counts"), ] promote_panels = [ MultiFieldPanel(COMMON_PANELS, "Common page configuration"), FieldPanel("feed_image"), ]
class EventPageSpeaker(TranslatableMixin, Orderable, LinkFields, ClusterableModel): page = ParentalKey( "tests.EventPage", related_name="speakers", related_query_name="speaker", on_delete=models.CASCADE, ) first_name = models.CharField("Name", max_length=255, blank=True) last_name = models.CharField("Surname", max_length=255, blank=True) image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) @property def name_display(self): return self.first_name + " " + self.last_name panels = [ FieldPanel("first_name"), FieldPanel("last_name"), FieldPanel("image"), MultiFieldPanel(LinkFields.panels, "Link"), InlinePanel("awards", label="Awards"), ] class Meta(TranslatableMixin.Meta, Orderable.Meta): pass
class GeoPage(Page): address = models.CharField(max_length=250, blank=True, null=True) location = models.PointField(srid=4326, null=True, blank=True) content_panels = Page.content_panels + [ InlinePanel("related_locations", label="Related locations"), ] location_panels = [ MultiFieldPanel( [ GeoAddressPanel("address", geocoder=geocoders.GOOGLE_MAPS), GoogleMapsPanel("location", address_field="address"), ], heading="Location", ) ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Content"), ObjectList(location_panels, heading="Location"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ])
class GeoPageWithLeaflet(Page): address = models.CharField( max_length=250, help_text=_("Search powered by Nominatim"), blank=True, null=True, ) location = models.PointField(srid=4326, null=True, blank=True) content_panels = Page.content_panels + [ InlinePanel("related_locations", label="Related locations"), ] location_panels = [ MultiFieldPanel( [ GeoAddressPanel("address", geocoder=geocoders.NOMINATIM), LeafletPanel("location", address_field="address"), ], heading="Location", ) ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Content"), ObjectList(location_panels, heading="Location"), ObjectList(Page.settings_panels, heading="Settings", classname="settings"), ])
class FormPage(AbstractEmailForm): def get_context(self, request): context = super().get_context(request) context["greeting"] = "hello world" return context # This is redundant (SubmissionsListView is the default view class), but importing # SubmissionsListView in this models.py helps us to confirm that this recipe # https://docs.wagtail.org/en/stable/reference/contrib/forms/customisation.html#customise-form-submissions-listing-in-wagtail-admin # works without triggering circular dependency issues - # see https://github.com/wagtail/wagtail/issues/6265 submissions_list_view_class = SubmissionsListView content_panels = [ FieldPanel("title", classname="full title"), InlinePanel("form_fields", label="Form fields"), MultiFieldPanel( [ FieldPanel("to_address", classname="full"), FieldPanel("from_address", classname="full"), FieldPanel("subject", classname="full"), ], "Email", ), ]
class JadeFormPage(AbstractEmailForm): template = "tests/form_page.jade" content_panels = [ FieldPanel("title", classname="full title"), InlinePanel("form_fields", label="Form fields"), MultiFieldPanel( [ FieldPanel("to_address", classname="full"), FieldPanel("from_address", classname="full"), FieldPanel("subject", classname="full"), ], "Email", ), ]
class StandardIndex(Page): """Index for the site""" parent_page_types = [Page] # A custom panel setup where all Promote fields are placed in the Content tab instead; # we use this to test that the 'promote' tab is left out of the output when empty content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("seo_title"), FieldPanel("slug"), InlinePanel("advert_placements", label="Adverts"), ] promote_panels = []
class FormPageWithRedirect(AbstractEmailForm): thank_you_redirect_page = models.ForeignKey( "wagtailcore.Page", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) def get_context(self, request): context = super(FormPageWithRedirect, self).get_context(request) context["greeting"] = "hello world" return context def render_landing_page(self, request, form_submission=None, *args, **kwargs): """ Renders the landing page OR if a receipt_page_redirect is chosen redirects to this page. """ if self.thank_you_redirect_page: return redirect(self.thank_you_redirect_page.url, permanent=False) return super(FormPageWithRedirect, self).render_landing_page(request, form_submission, *args, **kwargs) content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("thank_you_redirect_page"), InlinePanel("form_fields", label="Form fields"), MultiFieldPanel( [ FieldPanel("to_address", classname="full"), FieldPanel("from_address", classname="full"), FieldPanel("subject", classname="full"), ], "Email", ), ]
class FormPageWithCustomFormBuilder(AbstractEmailForm): """ A Form page that has a custom form builder and uses a custom form field model with additional field_type choices. """ form_builder = CustomFormBuilder content_panels = [ FieldPanel("title", classname="full title"), InlinePanel("form_fields", label="Form fields"), MultiFieldPanel( [ FieldPanel("to_address", classname="full"), FieldPanel("from_address", classname="full"), FieldPanel("subject", classname="full"), ], "Email", ), ]
def get_workflow_edit_handler(): """ Returns an edit handler which provides the "name" and "tasks" fields for workflow. """ # Note. It's a bit of a hack that we use edit handlers here. Ideally, it should be # made easier to reuse the inline panel templates for any formset. # Since this form is internal, we're OK with this for now. We might want to revisit # this decision later if we decide to allow custom fields on Workflows. panels = [ FieldPanel("name", heading=_("Give your workflow a name")), InlinePanel( "workflow_tasks", [ FieldPanel("task", widget=AdminTaskChooser(show_clear_link=False)), ], heading=_("Add tasks to your workflow"), label=_("Task"), icon="thumbtack", ), ] edit_handler = ObjectList(panels, base_form_class=WagtailAdminModelForm) return edit_handler.bind_to_model(Workflow)
class FormPageWithCustomSubmissionListView(AbstractEmailForm): """Form Page with customised submissions listing view""" intro = RichTextField(blank=True) thank_you_text = RichTextField(blank=True) def get_submissions_list_view_class(self): from .views import CustomSubmissionsListView return CustomSubmissionsListView def get_submission_class(self): return CustomFormPageSubmission def get_data_fields(self): data_fields = [ ("useremail", "User email"), ] data_fields += super().get_data_fields() return data_fields content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("intro", classname="full"), InlinePanel("form_fields", label="Form fields"), FieldPanel("thank_you_text", classname="full"), MultiFieldPanel( [ FieldPanel("to_address", classname="full"), FieldPanel("from_address", classname="full"), FieldPanel("subject", classname="full"), ], "Email", ), ]
class PersonPage(Page): first_name = models.CharField( max_length=255, verbose_name="First Name", ) last_name = models.CharField( max_length=255, verbose_name="Last Name", ) content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel("first_name"), FieldPanel("last_name"), ], "Person", ), InlinePanel("addresses", label="Address"), ] class Meta: verbose_name = "Person" verbose_name_plural = "Persons"
class HomePageCarouselItem(Orderable, AbstractCarouselItem): page = ParentalKey("HomePage", related_name="carousel_items", on_delete=models.CASCADE) class HomePageRelatedLink(Orderable, AbstractRelatedLink): page = ParentalKey("HomePage", related_name="related_links", on_delete=models.CASCADE) HomePage.content_panels = Page.content_panels + [ FieldPanel("body", classname="full"), InlinePanel("carousel_items", label="Carousel items"), InlinePanel("related_links", label="Related links"), ] # Standard pages class StandardPage(Page): page_ptr = models.OneToOneField(Page, parent_link=True, related_name="+", on_delete=models.CASCADE) intro = RichTextField(blank=True) body = RichTextField(blank=True) feed_image = models.ForeignKey( "wagtailimages.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="+", ) hero_image = models.ForeignKey( "images.CustomImage", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) book_file = models.ForeignKey( document_model_string, 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 SectionedRichTextPage(Page): content_panels = [ FieldPanel("title", classname="full title"), InlinePanel("sections"), ]
class FormPageWithCustomSubmission(AbstractEmailForm): """ This Form page: * Have custom submission model * Have custom related_name (see `FormFieldWithCustomSubmission.page`) * Saves reference to a user * Doesn't render html form, if submission for current user is present """ intro = RichTextField(blank=True) thank_you_text = RichTextField(blank=True) def get_context(self, request, *args, **kwargs): context = super().get_context(request) context["greeting"] = "hello world" return context def get_form_fields(self): return self.custom_form_fields.all() def get_data_fields(self): data_fields = [ ("useremail", "User email"), ] data_fields += super().get_data_fields() return data_fields def get_submission_class(self): return CustomFormPageSubmission def process_form_submission(self, form): form_submission = self.get_submission_class().objects.create( form_data=form.cleaned_data, page=self, user=form.user, ) if self.to_address: addresses = [x.strip() for x in self.to_address.split(",")] content = "\n".join([ x[1].label + ": " + str(form.data.get(x[0])) for x in form.fields.items() ]) send_mail( self.subject, content, addresses, self.from_address, ) # process_form_submission should now return the created form_submission return form_submission def serve(self, request, *args, **kwargs): if (self.get_submission_class().objects.filter( page=self, user__pk=request.user.pk).exists()): return TemplateResponse(request, self.template, self.get_context(request)) return super().serve(request, *args, **kwargs) content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("intro", classname="full"), InlinePanel("custom_form_fields", label="Form fields"), FieldPanel("thank_you_text", classname="full"), MultiFieldPanel( [ FieldPanel("to_address", classname="full"), FieldPanel("from_address", classname="full"), FieldPanel("subject", classname="full"), ], "Email", ), ]
class InlineStreamPage(Page): content_panels = [ FieldPanel("title", classname="full title"), InlinePanel("sections"), ]
class MultiSectionRichTextSnippet(ClusterableModel): panels = [ InlinePanel("sections"), ]