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 CustomUser(AbstractBaseUser, PermissionsMixin): identifier = ConvertedValueField(primary_key=True) username = models.CharField(max_length=100, unique=True) email = models.EmailField(max_length=255, blank=True) is_staff = models.BooleanField(default=True) is_active = models.BooleanField(default=True) first_name = models.CharField(max_length=50, blank=True) last_name = models.CharField(max_length=50, blank=True) country = models.CharField(max_length=100, blank=True) attachment = models.FileField(blank=True) USERNAME_FIELD = "username" REQUIRED_FIELDS = ["email"] objects = CustomUserManager() def get_full_name(self): return self.first_name + " " + self.last_name def get_short_name(self): return self.first_name panels = [ FieldPanel("first_name"), FieldPanel("last_name"), ]
class HomePage(Page): banner_title = models.CharField(max_length=100, blank=False, null=True) mission_statement = models.TextField(null=True) values_statement = models.TextField(null=True) highlighted_campaign = models.CharField(max_length=100, blank=False, null=True) highlighted_description = RichTextField(blank=False, null=True) action_network_embed_api_endpoint = models.URLField(blank=True, null=True) max_count = 1 content_panels = Page.content_panels + [ FieldPanel("banner_title"), FieldPanel("mission_statement"), FieldPanel("values_statement"), FieldPanel("highlighted_campaign"), FieldPanel("highlighted_description"), ] def get_context(self, request): context = super(HomePage, self).get_context(request) context["events"] = (Event.objects.filter( start__gte=datetime.now().date()).exclude( title__icontains="members only").order_by("start")[:4]) context["update"] = NewsPage.objects.live().latest("last_published_at") return context def serve(self, request): if request.method != "POST": return super().serve(request) request.session["email"] = request.POST["email"] return EmailFormView.as_view()(request)
class CustomRichTextFieldPage(Page): body = RichTextField(editor="custom") content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("body"), ]
class LinkFields(models.Model): link_external = models.URLField("External link", blank=True) link_page = models.ForeignKey( "wagtailcore.Page", null=True, blank=True, related_name="+", on_delete=models.CASCADE, ) link_document = models.ForeignKey( "wagtaildocs.Document", null=True, blank=True, related_name="+", on_delete=models.CASCADE, ) @property def link(self): if self.link_page: return self.link_page.url elif self.link_document: return self.link_document.url else: return self.link_external panels = [ FieldPanel("link_external"), FieldPanel("link_page"), FieldPanel("link_document"), ] class Meta: abstract = True
class DocumentPage(Page): date_published = models.DateField("Last Updated", blank=True, null=True) body = StreamField( [( "section", blocks.StreamBlock([ ("header", CharBlock()), ("text", blocks.RichTextBlock()), ("quote", BlockQuoteBlock()), ( "subsection", blocks.StreamBlock([ ("header", CharBlock()), ("text", blocks.TextBlock()), ( "subsubsection", blocks.StreamBlock([ ("header", CharBlock()), ("text", blocks.TextBlock()), ]), ), ]), ), ]), )], null=True, blank=True, use_json_field=True, ) content_panels = Page.content_panels + [ FieldPanel("date_published"), FieldPanel("body"), ]
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 FilePage(Page): file_field = models.FileField() content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("file_field"), ]
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 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 Event(models.Model): title = models.CharField(max_length=255) description = models.TextField() start = models.DateTimeField() end_time = models.TimeField(null=True, blank=True) address = models.CharField(max_length=30, null=True, blank=True) city = models.CharField(max_length=30, null=True, blank=True) state = models.CharField(max_length=2, null=True, blank=True) zip = models.IntegerField(null=True, blank=True) formation = models.ForeignKey( CommitteePage, null=True, on_delete=models.CASCADE, blank=True, related_name="events", ) url = models.URLField() status = models.CharField(max_length=50, null=True, blank=True) id = models.CharField(max_length=50, primary_key=True) panels = [ FieldPanel("title"), FieldPanel("description"), ] def __str__(self): return f"{self.title} {str(self.start)}"
def test_model_with_two_tabbed_panels_only(self): Publisher.settings_panels = [FieldPanel("name")] Publisher.promote_panels = [FieldPanel("headquartered_in")] warning_1 = checks.Warning( "Publisher.promote_panels will have no effect on modeladmin editing", hint= """Ensure that Publisher uses `panels` instead of `promote_panels`\ or set up an `edit_handler` if you want a tabbed editing interface. There are no default tabs on non-Page models so there will be no\ Promote tab for the promote_panels to render in.""", obj=Publisher, id="wagtailadmin.W002", ) warning_2 = checks.Warning( "Publisher.settings_panels will have no effect on modeladmin editing", hint= """Ensure that Publisher uses `panels` instead of `settings_panels`\ or set up an `edit_handler` if you want a tabbed editing interface. There are no default tabs on non-Page models so there will be no\ Settings tab for the settings_panels to render in.""", obj=Publisher, id="wagtailadmin.W002", ) checks_results = self.get_checks_result() self.assertIn(warning_1, checks_results) self.assertIn(warning_2, checks_results) # clean up for future checks delattr(Publisher, "settings_panels") delattr(Publisher, "promote_panels")
class RichTextFieldWithFeaturesPage(Page): body = RichTextField(features=["quotation", "embed", "made-up-feature"]) content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("body"), ]
class DefaultRichTextFieldPage(Page): body = RichTextField() content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("body"), ]
class TaggedPage(Page): tags = ClusterTaggableManager(through=TaggedPageTag, blank=True) content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("tags"), ]
class StreamPage(Page): body = StreamField( [ ("text", CharBlock()), ("rich_text", RichTextBlock()), ("image", ExtendedImageChooserBlock()), ( "product", StructBlock([ ("name", CharBlock()), ("price", CharBlock()), ]), ), ("raw_html", RawHTMLBlock()), ( "books", StreamBlock([ ("title", CharBlock()), ("author", CharBlock()), ]), ), ], use_json_field=False, ) api_fields = ("body", ) content_panels = [ FieldPanel("title"), FieldPanel("body"), ] preview_modes = []
class SecretPage(Page): boring_data = models.TextField() secret_data = models.TextField() content_panels = Page.content_panels + [ FieldPanel("boring_data"), FieldPanel("secret_data", permission="superuser"), ]
class BlogPageRelatedLink(Orderable): page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name="related_links") name = models.CharField(max_length=255) url = models.URLField() panels = [FieldPanel("name"), FieldPanel("url")] graphql_fields = [GraphQLString("name"), GraphQLString("url")]
class ContributorAdmin(ModelAdmin): model = Contributor panels = [ FieldPanel("last_name"), FieldPanel("phone_number"), FieldPanel("address"), ]
class Advert(models.Model): url = models.URLField(null=True, blank=True) text = models.CharField(max_length=255) panels = [FieldPanel("url"), FieldPanel("text")] graphql_fields = [GraphQLString("url"), GraphQLString("text")] def __str__(self): return self.text
class Person(models.Model): name = models.CharField(max_length=255) job = models.CharField(max_length=255) def __str__(self): return self.name panels = [FieldPanel("name"), FieldPanel("job")] graphql_fields = [GraphQLString("name"), GraphQLString("job")]
def test_model_with_single_tabbed_panel_and_edit_handler(self): Publisher.content_panels = [FieldPanel("name"), FieldPanel("headquartered_in")] Publisher.edit_handler = TabbedInterface(Publisher.content_panels) # no errors should occur self.assertEqual(self.get_checks_result(), []) # clean up for future checks delattr(Publisher, "content_panels") delattr(Publisher, "edit_handler")
class VisitorAdmin(ModelAdmin): model = Visitor panels = [ FieldPanel("last_name"), FieldPanel("phone_number"), FieldPanel("address"), ] edit_handler = TabbedInterface([ ObjectList(panels), ])
class SimplePage(Page): content = models.TextField() page_description = "A simple page description" content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("content"), ] def get_admin_display_title(self): return "%s (simple page)" % super().get_admin_display_title()
class CustomRichBlockFieldPage(Page): body = StreamField( [ ("rich_text", RichTextBlock(editor="custom")), ], use_json_field=False, ) content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("body"), ]
class FormClassAdditionalFieldPage(Page): location = models.CharField(max_length=255) body = RichTextField(blank=True) content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("location"), FieldPanel("body"), FieldPanel("code"), # not in model, see set base_form_class ] base_form_class = FormClassAdditionalFieldPageForm
class AdvertWithCustomPrimaryKey(ClusterableModel): advert_id = models.CharField(max_length=255, primary_key=True) url = models.URLField(null=True, blank=True) text = models.CharField(max_length=255) panels = [ FieldPanel("url"), FieldPanel("text"), ] def __str__(self): return self.text
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 AdvertWithCustomUUIDPrimaryKey(ClusterableModel): advert_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) url = models.URLField(null=True, blank=True) text = models.CharField(max_length=255) panels = [ FieldPanel("url"), FieldPanel("text"), ] def __str__(self): return self.text