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!

2c7f0a1020fbd01942166122190180f8?s=128

Lacey Williams Henschel

June 14, 2018
Tweet

Transcript

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

    Wagtail Space US 2018 ! @laceynwilliams | @revsys
  2. @laceynwilliams | @revsys

  3. @laceynwilliams | @revsys

  4. the docs are great ✓ upgrading ✓ ge*ng started ✓

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

    there too! @laceynwilliams | @revsys
  6. I'm a liar. @laceynwilliams | Source: pinocchiomuseum.org

  7. the page model @laceynwilliams | Source: Syd Wachs via Unsplash

  8. bit.ly/wagtail-page-docs bit.ly/wagtail-page-code @laceynwilliams | @revsys

  9. why do I care about the Page class? ✓ avoid

    duplica+on ✓ helpful methods ✓ dealing with Pages programma+cally @laceynwilliams | @revsys
  10. 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
  11. 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
  12. @laceynwilliams | Source: Wagtail docs

  13. 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
  14. @laceynwilliams | Source: Screenshot

  15. 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
  16. 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
  17. sprint ideas 1. Expand on "Page Models" in Usage Guide?

    @laceynwilliams | @revsys
  18. parent/child page types @laceynwilliams | Source: Harshil Gudka via Unsplash

  19. bit.ly/wagtail-page-rules @laceynwilliams | @revsys

  20. @laceynwilliams | @revsys

  21. ...but it's right there in the docs ✓ Docs were

    a li,le too light for me ✓ This rela3onship is important @laceynwilliams | @revsys
  22. 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
  23. parent_page_types What pages can create this kind of page? Who

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

    children be? @laceynwilliams | @revsys
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. sprint ideas 1. Expand on "Page Models" in Usage Guide?

    2. Add example to "Parent page / subpage type rules"? @laceynwilliams | @revsys
  31. DIY page saving @laceynwilliams | Source: Jasmin Schreiber via Unsplash

  32. why do I care about saving pages? ✓ content migra,ons

    ✓ backda,ng ✓ making changes to pages outside the UI @laceynwilliams | @revsys
  33. assumptions ✓ Model PostPage ✓ Index page PostIndexPage ✓ All

    data is valid @laceynwilliams | @revsys
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. Is there a better way? @laceynwilliams | @revsys

  41. 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
  42. DIY redirects @laceynwilliams | Source: Jamie Street via Unsplash

  43. why do I care about redirects? ✓ avoiding 404s in

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

    Redirects are permanent ✓ URL definitely 404s ✓ Redirec9ng to a Page instance @laceynwilliams | @revsys
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. using the User model @laceynwilliams | Source: WOCinTech Chat

  53. bit.ly/wagtail-custom-user @laceynwilliams | @revsys

  54. why do I care about the User model? ✓ People

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

  56. # 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
  57. # 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
  58. # 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
  59. So then just ForeignKey directly to TeamMemberPage from PostPage ,

    right? @laceynwilliams | @revsys
  60. # 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
  61. @laceynwilliams | Source: NeONBRAND via Unsplash

  62. # 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
  63. # 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
  64. # 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
  65. 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
  66. Look again at those docs. That's here. That's home. That's

    us. — Carl Sagan, probably @laceynwilliams | Source: Ma4eo Fusco via Unsplash
  67. ! @laceynwilliams ! lacey@revsys.com ! revsys.com ! laceyhenschel.com @laceynwilliams |

    @revsys