Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What the Wagtail Docs Don't Tell You

What the Wagtail Docs Don't Tell You

The importance of the Page model, saving Pages and Redirects programmatically, and doing more with the User model!

Lacey Williams Henschel

June 14, 2018
Tweet

More Decks by Lacey Williams Henschel

Other Decks in Programming

Transcript

  1. What the Wagtail Docs Don't Tell You Lacey Williams Henschel

    Wagtail Space US 2018 ! @laceynwilliams | @revsys
  2. the docs are great ✓ upgrading ✓ ge*ng started ✓

    end users @laceynwilliams | @revsys
  3. ... but there are some possibili0es for sprint projects in

    there too! @laceynwilliams | @revsys
  4. why do I care about the Page class? ✓ avoid

    duplica+on ✓ helpful methods ✓ dealing with Pages programma+cally @laceynwilliams | @revsys
  5. class Page(AbstractPage): title = models.CharField() draft_title = models.CharField() slug =

    models.SlugField() live = models.BooleanField() url_path = models.TextField() owner = models.ForeignKey(settings.AUTH_USER_MODEL) seo_title = models.CharField() show_in_menus = models.BooleanField() search_description = models.TextField() go_live_at = models.DateTimeField() expire_at = models.DateTimeField() expired = models.BooleanField() locked = models.BooleanField() first_published_at = models.DateTimeField() last_published_at = models.DateTimeField() latest_revision_created_at = models.DateTimeField() live_revision = models.ForeignKey() @laceynwilliams | @revsys
  6. class Page(AbstractPage): title = models.CharField() draft_title = models.CharField() slug =

    models.SlugField() live = models.BooleanField() url_path = models.TextField() owner = models.ForeignKey(settings.AUTH_USER_MODEL) seo_title = models.CharField() show_in_menus = models.BooleanField() search_description = models.TextField() go_live_at = models.DateTimeField() expire_at = models.DateTimeField() expired = models.BooleanField() locked = models.BooleanField() first_published_at = models.DateTimeField() last_published_at = models.DateTimeField() latest_revision_created_at = models.DateTimeField() live_revision = models.ForeignKey() @laceynwilliams | @revsys
  7. class Page(AbstractPage): title = models.CharField() draft_title = models.CharField() slug =

    models.SlugField() live = models.BooleanField() url_path = models.TextField() owner = models.ForeignKey(settings.AUTH_USER_MODEL) seo_title = models.CharField() show_in_menus = models.BooleanField() search_description = models.TextField() go_live_at = models.DateTimeField() expire_at = models.DateTimeField() expired = models.BooleanField() locked = models.BooleanField() first_published_at = models.DateTimeField() last_published_at = models.DateTimeField() latest_revision_created_at = models.DateTimeField() live_revision = models.ForeignKey() @laceynwilliams | @revsys
  8. class Page(AbstractPage): title = models.CharField() draft_title = models.CharField() slug =

    models.SlugField() live = models.BooleanField() url_path = models.TextField() owner = models.ForeignKey(settings.AUTH_USER_MODEL) seo_title = models.CharField() show_in_menus = models.BooleanField() search_description = models.TextField() go_live_at = models.DateTimeField() expire_at = models.DateTimeField() expired = models.BooleanField() locked = models.BooleanField() first_published_at = models.DateTimeField() last_published_at = models.DateTimeField() latest_revision_created_at = models.DateTimeField() live_revision = models.ForeignKey() @laceynwilliams | @revsys
  9. class Page(AbstractPage): """ Wildly truncated """ def save_revision(self, user=None, submitted_for_moderation=False,

    approved_go_live_at=None, changed=True): ... revision = self.revisions.create( content_json=self.to_json(), user=user, submitted_for_moderation=submitted_for_moderation, approved_go_live_at=approved_go_live_at, ) ... return revision @laceynwilliams | @revsys
  10. ...but it's right there in the docs ✓ Docs were

    a li,le too light for me ✓ This rela3onship is important @laceynwilliams | @revsys
  11. from wagtail.core.models import Page class PostIndexPage(Page): # some attributes... parent_page_types

    = ['homepage.Homepage'] subpage_types = ['posts.PostPage'] class PostPage(Page): # some attributes... parent_page_types = ['posts.PostIndexPage'] @laceynwilliams | @revsys
  12. parent_page_types What pages can create this kind of page? Who

    can your parents be? @laceynwilliams | @revsys
  13. subpage_types What pages can this page create? Who can your

    children be? @laceynwilliams | @revsys
  14. from wagtail.core.models import Page class PostIndexPage(Page): # some attributes... parent_page_types

    = ['homepage.Homepage'] subpage_types = ['posts.PostPage'] class PostPage(Page): # some attributes... parent_page_types = ['posts.PostIndexPage'] @laceynwilliams | @revsys
  15. from wagtail.core.models import Page class PostIndexPage(Page): # some attributes... parent_page_types

    = ['homepage.Homepage'] subpage_types = ['posts.PostPage'] class PostPage(Page): # some attributes... parent_page_types = ['posts.PostIndexPage'] @laceynwilliams | @revsys
  16. from wagtail.core.models import Page class PostIndexPage(Page): # some attributes... parent_page_types

    = ['homepage.Homepage'] subpage_types = ['posts.PostPage'] class PostPage(Page): # some attributes... parent_page_types = ['posts.PostIndexPage'] @laceynwilliams | @revsys
  17. from wagtail.core.models import Page class PostIndexPage(Page): # some attributes... parent_page_types

    = ['homepage.Homepage'] subpage_types = ['posts.PostPage'] class PostPage(Page): # some attributes... parent_page_types = ['posts.PostIndexPage'] @laceynwilliams | @revsys
  18. If you want to limit a page to have only

    one type of child and limit its child to have only one type of parent you have to tell both models. @laceynwilliams | @revsys
  19. sprint ideas 1. Expand on "Page Models" in Usage Guide?

    2. Add example to "Parent page / subpage type rules"? @laceynwilliams | @revsys
  20. why do I care about saving pages? ✓ content migra,ons

    ✓ backda,ng ✓ making changes to pages outside the UI @laceynwilliams | @revsys
  21. from .models import PostPage, PostIndexPage def create_new_post(fields): post = PostPage()

    post.title = fields['title'] post.latest_revision_created_at = fields['latest_revision_created_at'] post.first_published_at = fields['first_published_at'] # rest of fields post_index = PostIndexPage.objects.get(slug='posts') post_index.add_child(instance=post) revision = post.save_revision(submitted_for_moderation=False) post.save() if post.live: revision.publish() return post @laceynwilliams | @revsys
  22. from .models import PostPage, PostIndexPage def create_new_post(fields): post = PostPage()

    post.title = fields['title'] post.latest_revision_created_at = fields['latest_revision_created_at'] post.first_published_at = fields['first_published_at'] # rest of fields post_index = PostIndexPage.objects.get(slug='posts') post_index.add_child(instance=post) revision = post.save_revision(submitted_for_moderation=False) post.save() if post.live: revision.publish() return post @laceynwilliams | @revsys
  23. from .models import PostPage, PostIndexPage def create_new_post(fields): post = PostPage()

    post.title = fields['title'] post.latest_revision_created_at = fields['latest_revision_created_at'] post.first_published_at = fields['first_published_at'] # rest of fields post_index = PostIndexPage.objects.get(slug='posts') post_index.add_child(instance=post) revision = post.save_revision(submitted_for_moderation=False) post.save() if post.live: revision.publish() return post @laceynwilliams | @revsys
  24. from .models import PostPage, PostIndexPage def create_new_post(fields): post = PostPage()

    post.title = fields['title'] post.latest_revision_created_at = fields['latest_revision_created_at'] post.first_published_at = fields['first_published_at'] # rest of fields post_index = PostIndexPage.objects.get(slug='posts') post_index.add_child(instance=post) revision = post.save_revision(submitted_for_moderation=False) post.save() if post.live: revision.publish() return post @laceynwilliams | @revsys
  25. from .models import PostPage, PostIndexPage def create_new_post(fields): post = PostPage()

    post.title = fields['title'] post.latest_revision_created_at = fields['latest_revision_created_at'] post.first_published_at = fields['first_published_at'] # rest of fields post_index = PostIndexPage.objects.get(slug='posts') post_index.add_child(instance=post) revision = post.save_revision(submitted_for_moderation=False) post.save() if post.live: revision.publish() return post @laceynwilliams | @revsys
  26. from .models import PostPage, PostIndexPage def create_new_post(fields): post = PostPage()

    post.title = fields['title'] post.latest_revision_created_at = fields['latest_revision_created_at'] post.first_published_at = fields['first_published_at'] # rest of fields post_index = PostIndexPage.objects.get(slug='posts') post_index.add_child(instance=post) revision = post.save_revision(submitted_for_moderation=False) post.save() if post.live: revision.publish() return post @laceynwilliams | @revsys
  27. sprint ideas 1. Expand on "Page Models" in Usage Guide?

    2. Add example to "Parent page / subpage type rules"? 3. Method to add a new page instance? Or more docs? @laceynwilliams | @revsys
  28. why do I care about redirects? ✓ avoiding 404s in

    content migra1ons ✓ needing to add a lot of redirects @laceynwilliams | @revsys
  29. assumptions ✓ No custom Redirect class ✓ One site ✓

    Redirects are permanent ✓ URL definitely 404s ✓ Redirec9ng to a Page instance @laceynwilliams | @revsys
  30. from wagtail.contrib.redirects.models import Redirect def add_redirect(old_url, post_page): redirect = Redirect()

    redirect.old_path = old_url.rstrip('/') redirect.is_permanent = True redirect.redirect_page = post_page redirect.save() return redirect @laceynwilliams | @revsys
  31. from wagtail.contrib.redirects.models import Redirect def add_redirect(old_url, post_page): redirect = Redirect()

    redirect.old_path = old_url.rstrip('/') redirect.is_permanent = True redirect.redirect_page = post_page redirect.save() return redirect @laceynwilliams | @revsys
  32. from wagtail.contrib.redirects.models import Redirect def add_redirect(old_url, post_page): redirect = Redirect()

    redirect.old_path = old_url.rstrip('/') redirect.is_permanent = True redirect.redirect_page = post_page redirect.save() return redirect @laceynwilliams | @revsys
  33. from wagtail.contrib.redirects.models import Redirect def add_redirect(old_url, post_page): redirect = Redirect()

    redirect.old_path = old_url.rstrip('/') redirect.is_permanent = True redirect.redirect_page = post_page redirect.save() return redirect @laceynwilliams | @revsys
  34. from wagtail.contrib.redirects.models import Redirect def add_redirect(old_url, post_page): redirect = Redirect()

    redirect.old_path = old_url.rstrip('/') redirect.is_permanent = True redirect.redirect_page = post_page redirect.save() return redirect @laceynwilliams | @revsys
  35. from wagtail.contrib.redirects.models import Redirect def add_redirect(old_url, post_page): redirect = Redirect()

    redirect.old_path = old_url.rstrip('/') redirect.is_permanent = True redirect.redirect_page = post_page redirect.save() return redirect @laceynwilliams | @revsys
  36. sprint ideas 1. Expand on "Page Models" in Usage Guide?

    2. Add example to "Parent page / subpage type rules"? 3. Method to add a new page instance? Or more docs? 4. Method to add redirect programmatically? @laceynwilliams | @revsys
  37. why do I care about the User model? ✓ People

    ✓ Easy access in admin @laceynwilliams | @revsys
  38. '

  39. # team/models.py from django.contrib.auth import get_user_model from wagtail.core.models import Page

    User = get_user_model() class TeamMemberPage(Page): ... user = models.ForeignKey(User) @laceynwilliams | @revsys
  40. # team/models.py from django.contrib.auth import get_user_model from wagtail.core.models import Page

    User = get_user_model() class TeamMemberPage(Page): ... user = models.ForeignKey(User) @laceynwilliams | @revsys
  41. # team/models.py from django.contrib.auth import get_user_model from wagtail.core.models import Page

    User = get_user_model() class TeamMemberPage(Page): ... user = models.ForeignKey(User) @laceynwilliams | @revsys
  42. # posts/models.py from django.contrib.auth import get_user_model from wagtail.core.models import Page

    User = get_user_model() class PostPage(Page): author = models.ForeignKey(User) # or author = models.ForeignKey('team.TeamMemberPage') @laceynwilliams | @revsys
  43. # posts/models.py from wagtail.admin.edit_handlers import PageChooserPanel from wagtail.core.models import Page

    class PostPage(Page): author = models.ForeignKey('wagtailcore.Page') content_panels = Page.content_panels + [ PageChooserPanel('author', ['team.TeamMemberPage']), ] @laceynwilliams | @revsys
  44. # posts/models.py from wagtail.admin.edit_handlers import PageChooserPanel from wagtail.core.models import Page

    class PostPage(Page): author = models.ForeignKey('wagtailcore.Page') content_panels = Page.content_panels + [ PageChooserPanel('author', ['team.TeamMemberPage']), ] @laceynwilliams | @revsys
  45. # posts/models.py from wagtail.admin.edit_handlers import PageChooserPanel from wagtail.core.models import Page

    class PostPage(Page): author = models.ForeignKey('wagtailcore.Page') content_panels = Page.content_panels + [ PageChooserPanel('author', ['team.TeamMemberPage']), ] @laceynwilliams | @revsys
  46. sprint ideas 1. Expand on "Page Models" in Usage Guide?

    2. Add example to "Parent page / subpage type rules"? 3. Method to add a new page instance? Or more docs? 4. Method to add redirect programmatically? 5. Expand on User model docs? @laceynwilliams | @revsys
  47. Look again at those docs. That's here. That's home. That's

    us. — Carl Sagan, probably @laceynwilliams | Source: Ma4eo Fusco via Unsplash