Skip to content

Instantly share code, notes, and snippets.

@cnk
Created November 26, 2024 17:27
Show Gist options
  • Save cnk/c50ea546b66449c7930bf65db4ad7823 to your computer and use it in GitHub Desktop.
Save cnk/c50ea546b66449c7930bf65db4ad7823 to your computer and use it in GitHub Desktop.
Overriding RoutablePage to add caching headers
class BasePage(RobotsTxtMixin, 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.
* 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, duration=DEFAULT_PAGE_CACHE_TIME):
"""
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(duration)
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
#############
class MasterCalendarPage2(RoutableBasePage):
"""
A MasterCalendarPage acts as the entry point to the Master Calendar functionality on a given Site. Every part of the
Master Calendar for its Site is served by this Page.
"""
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment