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 MetadataPageMixin(WagtailImageMetadataMixin, models.Model): """An implementation of MetadataMixin for Wagtail pages.""" search_image = models.ForeignKey(get_image_model_string(), null=True, blank=True, related_name='+', on_delete=models.SET_NULL, verbose_name=gettext_lazy('Search image')) promote_panels = [ MultiFieldPanel([ FieldPanel('slug'), FieldPanel('seo_title'), FieldPanel('show_in_menus'), FieldPanel('search_description'), ImageChooserPanel('search_image'), ], gettext_lazy('Common page configuration')), ] def get_meta_url(self): return self.full_url def get_meta_title(self): return self.seo_title or self.title def get_meta_description(self): return self.search_description def get_meta_image(self): return self.search_image class Meta: abstract = True
class EventPageSpeaker(Orderable, AbstractLinkFields): page = ParentalKey("EventPage", related_name="speakers", 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="+", ) api_fields = ( "first_name", "last_name", "image", ) panels = [ FieldPanel("first_name"), FieldPanel("last_name"), FieldPanel("image"), MultiFieldPanel(AbstractLinkFields.panels, "Link"), ]
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 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 ClassicGeoPage(Page): address = models.CharField(max_length=250, blank=True, null=True) location = models.CharField(max_length=250, blank=True, null=True) content_panels = Page.content_panels + [ MultiFieldPanel( [ GeoAddressPanel("address", geocoder=geocoders.GOOGLE_MAPS), GoogleMapsPanel( "location", address_field="address", hide_latlng=True), ], _("Geo details"), ), ] def get_context(self, request): data = super(ClassicGeoPage, self).get_context(request) return data @cached_property def point(self): from wagtailgeowidget.helpers import geosgeometry_str_to_struct return geosgeometry_str_to_struct(self.location) @property def lat(self): return self.point["y"] @property def lng(self): return self.point["x"]
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 AbstractCarouselItem(AbstractLinkFields): image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) embed_url = models.URLField("Embed URL", blank=True) caption = models.CharField(max_length=255, blank=True) api_fields = ( "image", "embed_url", "caption", ) + AbstractLinkFields.api_fields panels = [ FieldPanel("image"), FieldPanel("embed_url"), FieldPanel("caption"), MultiFieldPanel(AbstractLinkFields.panels, "Link"), ] class Meta: abstract = True
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 RelatedLink(LinkFields): title = models.CharField(max_length=255, help_text="Link title") panels = [ FieldPanel("title"), MultiFieldPanel(LinkFields.panels, "Link"), ] class Meta: abstract = True
class AbstractRelatedLink(AbstractLinkFields): title = models.CharField(max_length=255, help_text="Link title") api_fields = ("title", ) + AbstractLinkFields.api_fields panels = [ FieldPanel("title"), MultiFieldPanel(AbstractLinkFields.panels, "Link"), ] class Meta: abstract = True
class RelatedLink(models.Model): title = models.CharField(max_length=255, ) link = models.ForeignKey(Page, on_delete=models.CASCADE, related_name="+") panels = [ MultiFieldPanel( [ FieldPanel("title"), FieldPanel("link"), ], heading="Related Link", ), ]
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 GeoLocation(models.Model): title = models.CharField(max_length=255) address = models.CharField(max_length=250, blank=True, null=True) zoom = models.SmallIntegerField(blank=True, null=True) location = models.PointField(srid=4326, null=True, blank=True) panels = [ FieldPanel("title"), MultiFieldPanel( [ GeoAddressPanel("address", geocoder=geocoders.GOOGLE_MAPS), FieldPanel("zoom"), GoogleMapsPanel( "location", address_field="address", zoom_field="zoom"), ], _("Geo details"), ), ]
class ClassicGeoPageWithLeafletAndZoom(Page): address = models.CharField( max_length=250, help_text=_("Search powered by Nominatim"), blank=True, null=True, ) location = models.CharField(max_length=250, blank=True, null=True) zoom = models.SmallIntegerField(blank=True, null=True) content_panels = Page.content_panels + [ MultiFieldPanel( [ GeoAddressPanel("address", geocoder=geocoders.NOMINATIM), FieldPanel("zoom"), LeafletPanel( "location", address_field="address", zoom_field="zoom", hide_latlng=True, ), ], _("Geo details"), ), ] def get_context(self, request): data = super().get_context(request) return data @cached_property def point(self): from wagtailgeowidget.helpers import geosgeometry_str_to_struct return geosgeometry_str_to_struct(self.location) @property def lat(self): return self.point["y"] @property def lng(self): return self.point["x"]
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", ), ]
class GeoLocationWithLeaflet(models.Model): title = models.CharField(max_length=255) address = models.CharField( max_length=250, help_text=_("Search powered by Nominatim"), blank=True, null=True, ) zoom = models.SmallIntegerField(blank=True, null=True) location = models.PointField(srid=4326, null=True, blank=True) panels = [ FieldPanel("title"), MultiFieldPanel( [ GeoAddressPanel("address", geocoder=geocoders.NOMINATIM), FieldPanel("zoom"), LeafletPanel( "location", address_field="address", zoom_field="zoom"), ], _("Geo details"), ), ]
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 StandardPageRelatedLink(Orderable, AbstractRelatedLink): page = ParentalKey("StandardPage", related_name="related_links", on_delete=models.CASCADE) StandardPage.content_panels = Page.content_panels + [ FieldPanel("intro", classname="full"), InlinePanel("carousel_items", label="Carousel items"), FieldPanel("body", classname="full"), InlinePanel("related_links", label="Related links"), ] StandardPage.promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), FieldPanel("feed_image"), ] class StandardIndexPage(Page): page_ptr = models.OneToOneField(Page, parent_link=True, related_name="+", on_delete=models.CASCADE) intro = RichTextField(blank=True) feed_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL,
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", ), ]