Created
October 2, 2023 16:32
-
-
Save cnk/44f6118476694c8319d52198aac717a0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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