Skip to content

Instantly share code, notes, and snippets.

@cnk
Created October 2, 2023 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cnk/44f6118476694c8319d52198aac717a0 to your computer and use it in GitHub Desktop.
Save cnk/44f6118476694c8319d52198aac717a0 to your computer and use it in GitHub Desktop.
from wagtail.contrib.routable_page.models import RoutablePageMixin
from wagtail.models import Page, PageViewRestriction
from robots_txt.models import RobotsTxtMixin
from ..utils import URLMixin
# Typical cache durations, defined in seconds.
DEFAULT_PAGE_CACHE_TIME = 60 * 5 # 5 minutes
TWENTY_FOUR_HOURS = 60 * 60 * 24
PRIVATE_PAGE_CACHE_HEADER = 'private, max-age=0, s-maxage=0'
PUBLIC_PAGE_CACHE_HEADER_DEFAULT = f'public, max-age={DEFAULT_PAGE_CACHE_TIME}'
# To use this template, import it and then call PUBLIC_PAGE_CACHE_HEADER_TEMPLATE.format(num_seconds).
PUBLIC_PAGE_CACHE_HEADER_TEMPLATE = 'public, max-age={}'
# How long to cache template fragments. We cache for a day as of 2023-06-22, but that may get tweaked as we get more
# experience with template fragment caching.
TEMPLATE_FRAGMENT_CACHE_TIME = 60 * 60 * 24 # 24 hours
class BasePage(RobotsTxtMixin, URLMixin, Page):
"""
BasePage exists to provide the default functionality that we want all (or nearly all) of our Page models to have.
Currently, that includes the following:
* RobotsTxtMixin adds the ability to place the Page into our robots.txt file, to hide it from search engines.
* URLMixin changes how Pages generate their own URLs, to better support our multitenancy system.
* The serve() method in this class adds Cache-Control headers to every Page when it gets served by Wagtail.
The values for the Cache-Control headers are a work in progress, and for now are basically either "don't cache
locally or on Cloudflare" OR "please cache on Cloudflare".
I am not setting a browser cache time because it makes it harder for me to test rules. And I am using the more
general "CDN-Cache-Control" header so I can see that the value is getting served. When I use
"Cloudflare-CDN-Cache-Control" the header gets stripped, so I can't be sure it got served or what value it had.
"""
def is_private(self):
restricted_pages = PageViewRestriction.objects.values('page_id')
return self.get_ancestors(inclusive=True).filter(id__in=restricted_pages).exists()
def _public_cache_control_header(self):
"""
Override this in a subclass to define a custom public cache control header, most likely by using
PUBLIC_PAGE_CACHE_HEADER_TEMPLATE.format(some_other_duration).
"""
return PUBLIC_PAGE_CACHE_HEADER_TEMPLATE.format(DEFAULT_PAGE_CACHE_TIME)
def add_cache_control_headers(self, response):
"""
Adds our custom cache control headers to the given HttpResponse object.
"""
if self.is_private():
response.headers['Cache-Control'] = PRIVATE_PAGE_CACHE_HEADER
else:
response.headers['CDN-Cache-Control'] = self._public_cache_control_header()
# To enable chaining, this method also returns the response.
return response
def serve(self, request, *args, **kwargs):
"""
Add Cache-Control headers to all pages served, depending on page privacy.
"""
response = super().serve(request, *args, **kwargs)
return self.add_cache_control_headers(response)
def serve_preview(self, request, mode_name):
"""
Adds the appropriate Cache-Control header for Page previews.
"""
response = super().serve_preview(request, mode_name)
response.headers['Cache-Control'] = PRIVATE_PAGE_CACHE_HEADER
return response
class Meta:
abstract = True
class RoutableBasePage(RoutablePageMixin, BasePage):
"""
A RoutablePage class based on BasePage.
"""
def render(self, request, *args, template=None, context_overrides=None, **kwargs):
"""
We override this method so that every time a RoutablePage view is rendered, we add our cache control headers.
"""
response = super().render(request, *args, template=template, context_overrides=context_overrides, **kwargs)
return self.add_cache_control_headers(response)
class Meta:
abstract = True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment