Skip to content

Instantly share code, notes, and snippets.

@johnsardine
Created August 21, 2017 16:50
Show Gist options
  • Save johnsardine/29a6b26a91d9b1ca8384c0b5a2e76ce4 to your computer and use it in GitHub Desktop.
Save johnsardine/29a6b26a91d9b1ca8384c0b5a2e76ce4 to your computer and use it in GitHub Desktop.
Simple cache bust technique for Flask projects. `/static/main.css` becomes `/static/main.123456789.css`
import re
from flask import Flask
from flask.helpers import send_from_directory
# Subclass Flask and override send_static_file method
class CustomStaticFlask(Flask):
def send_static_file(self, filename):
"""Overrides to filter out cache buster from file path
Input images/file.{hash}.css
Output images/file.css
"""
if not self.has_static_folder:
raise RuntimeError('No static folder for this object')
# Replace cache bust key in filename
cache_bust_enabled = self.config.get('STATIC_CACHEBUST_ENABLED')
allowed_extensions = self.config.get('STATIC_CACHEBUST_EXTENSIONS')
if cache_bust_enabled:
filename = re.sub(r"\.(\d*)\.(" + allowed_extensions + ")$",
r".\2",
filename)
cache_timeout = self.get_send_file_max_age(filename)
return send_from_directory(self.static_folder, filename,
cache_timeout=cache_timeout)
# Create your app based on the subclass
def create_app(config=None):
app = CustomStaticFlask(__name__)
import os
class BaseConfig(object):
STATIC_CACHEBUST_ENABLED = \
os.environ.get("STATIC_CACHEBUST_ENABLED", "False") == "True"
STATIC_CACHEBUST_EXTENSIONS = \
os.environ.get("STATIC_CACHEBUST_EXTENSIONS",
"css|js|png|svg|jpg|jpeg")
from flask import url_for
@app.context_processor
def override_url_for():
return dict(url_for=dated_url_for)
def dated_url_for(endpoint, **values):
cache_bust_enabled = app.config.get('STATIC_CACHEBUST_ENABLED')
allowed_extensions = app.config.get('STATIC_CACHEBUST_EXTENSIONS')
if endpoint == 'static':
filename = values.get('filename', None)
if filename:
file_path = os.path.join(app.root_path,
endpoint, filename)
if os.path.exists(file_path):
file_changed_timestamp = int(os.stat(file_path).st_mtime)
filename_split = os.path.splitext(filename)
extension_matches_allowed =\
re.match(r"\.(" + allowed_extensions + ")",
filename_split[1])
if cache_bust_enabled and extension_matches_allowed:
cache_bust_key = ('.', str(file_changed_timestamp))
cache_bust_filename = \
(''.join(cache_bust_key)).join(filename_split)
values['filename'] = cache_bust_filename
return url_for(endpoint, **values)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment