Requiring staff permissions on your Wagtail site
Learning Wagtail requires breaking some habits formed by working in Django. The biggest paradigm shift is that when creating Pages in Wagtail the view functionality is provided by the Model itself in a method named serve.
Decorating each of your Page-derived models individually can be a pain and is more messy than DRY. Here's a simple way to override the default behavior of the serve method and require staff-level permissions for your Wagtail site. This was particularly useful to me while developing a Wagtail site that shared a Django project with dozens of existing live applications.
At the top of your_wagtail_project/models.py, do the following.
from django.http import HttpResponseRedirect # from wagtail.wagtailcore.models import Page # This is the standard Page import; when you're ready to serve your new Wagtail site to the public, comment out the custom class override below and import Page directly from Wagtail from wagtail.wagtailcore.models import Page as PageBase class Page(PageBase): ''' PROTECTS CMS PAGES FROM PUBLIC. To remove, revert import of wagtail Page back to original name and comment out this class ''' class Meta: abstract = True def serve(self, request, *args, **kwargs): # Need to test some other permission? Do it here. if request.user.is_staff: return super(Page,self).serve(request, *args, **kwargs) return HttpResponseRedirect(reverse('admin:login')+"?next="+request.path) ''' Go about your business :) ''' class FAQPage(Page): pass class InfoPage(Page): pass
When the pages are called, the serve method forces a redirect to the login if the the user isn't a staff member. Each page below this is now inheriting the abstract model we created, and calling our custom serve method.
Simply comment out your custom Page class and revert to importing the standard Page class by it's original name. It's probably worth keeping around in case you ever want to switch back to protected mode. IF you do that, you'll probably want to make a custom property that overrides the database value for show_in_menus to always be safe to keep it hidden from the public.
from wagtail.wagtailcore.models import Page # from wagtail.wagtailcore.models import Page as PageBase # class Page(PageBase): # ...
Well, that's a piece of cake. Let's just use the method above to create some distinctions!
from django.http import HttpResponseRedirect from wagtail.wagtailadmin.edit_handlers import MultiFieldPanel from wagtail.wagtailcore.models import Page # This is the standard Page import class StaffOnlyPage(Page): search_fields =  # Let's hide this from all searches; if you really need to show in searches to staff members, override the search method based on permissions class Meta: abstract = True def serve(self, request, *args, **kwargs): if request.user.is_staff: return super(Page,self).serve(request, *args, **kwargs) return HttpResponseRedirect(reverse('admin:login')+"?next="+request.path) StaffOnlyPage.promote_panels = [ FieldPanel('slug'), FieldPanel('seo_title'), # FieldPanel('show_in_menus'), # Commented out so that StaffOnlyPages don't display the 'show_in_menus' field in the CMS/admin. This is False by default, so we're preventing these pages from being shown in our menu system. FieldPanel('search_description'), ] class FAQPage(Page): pass class StaffInfoPage(StaffOnlyPage): pass
Now we have a page where we can release news and info to internal staff members that is protected from the public; it won't show up in search results or menus. If existing pages were converted to this page type then be sure to set show_in_menus to False for each. Why not get adventurous and write a migration that uses RunPython to do so?
Have you done anything similar? Feel free to share!
Want to work together? Send an email.
©2018 Ian Price / Red Mountain GIS