CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-flask-caching

Adds caching support to Flask applications.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

template-caching.mddocs/

Template Fragment Caching

Jinja2 template integration for caching expensive template fragments. This feature allows caching portions of templates to improve rendering performance, especially useful for complex layouts, database-driven content, or expensive template operations.

Capabilities

Jinja2 Cache Extension

Flask-Caching automatically registers a Jinja2 extension that provides template-level caching control through the {% cache %} template tag.

class CacheExtension(Extension):
    """
    Jinja2 extension for template fragment caching.
    Automatically registered when Cache is initialized with with_jinja2_ext=True.
    """

# Template syntax
"""
{% cache timeout key1[, key2, ...] %}
...template content...
{% endcache %}
"""

Automatic Registration:

from flask import Flask
from flask_caching import Cache

app = Flask(__name__)
cache = Cache(app)  # Jinja2 extension automatically registered

# Disable automatic registration
cache = Cache(app, with_jinja2_ext=False)

Basic Template Caching

Cache template fragments with timeout and optional cache keys.

{# Cache for 5 minutes with default key #}
{% cache 300 %}
<div class="expensive-content">
  {% for item in expensive_database_query() %}
    <p>{{ item.title }}: {{ item.description }}</p>
  {% endfor %}
</div>
{% endcache %}

{# Cache with custom key #}
{% cache 600 "sidebar_content" %}
<aside class="sidebar">
  {{ render_complex_sidebar() }}
</aside>
{% endcache %}

{# Cache with multiple keys for uniqueness #}
{% cache 300 "user_dashboard" user.id %}
<div class="dashboard">
  <h2>Welcome {{ user.name }}</h2>
  {{ render_user_stats(user.id) }}
</div>
{% endcache %}

Dynamic Cache Keys

Use template variables and expressions to create dynamic cache keys based on context.

{# Cache per user and page #}
{% cache 600 "user_content" user.id request.endpoint %}
<div class="personalized-content">
  {{ get_user_recommendations(user.id) }}
</div>
{% endcache %}

{# Cache with date-based key for daily content #}
{% cache 3600 "daily_stats" current_date.strftime('%Y-%m-%d') %}
<div class="daily-statistics">
  {{ calculate_daily_metrics() }}
</div>
{% endcache %}

{# Cache with conditional keys #}
{% cache 300 "product_list" category.id, ("sale" if on_sale else "regular") %}
<div class="product-grid">
  {% for product in get_products(category.id, on_sale) %}
    {{ render_product_card(product) }}
  {% endfor %}
</div>
{% endcache %}

Cache Control Operations

Special cache operations within templates.

{# Delete cached content #}
{% cache 'del' "sidebar_content" %}
{# This will delete the cached content and re-render #}
<aside class="sidebar">
  {{ render_complex_sidebar() }}
</aside>  
{% endcache %}

{# Cache with no timeout (never expires) #}
{% cache None "permanent_footer" %}
<footer>
  {{ render_footer_content() }}
</footer>
{% endcache %}

Programmatic Cache Key Generation

Generate cache keys programmatically for template fragments.

def make_template_fragment_key(
    fragment_name: str, 
    vary_on: Optional[List[str]] = None
) -> str:
    """
    Generate cache key for template fragments.
    
    Parameters:
    - fragment_name: Base name for the cache fragment
    - vary_on: List of values to vary the cache key on
    
    Returns:
    String cache key for the template fragment
    """

Usage in Python Code:

from flask_caching import make_template_fragment_key

# Generate keys manually
cache_key = make_template_fragment_key('user_profile', [str(user.id)])
cached_content = cache.get(cache_key)

if cached_content is None:
    # Render template fragment
    cached_content = render_template_string("""
        <div class="profile">{{ user.name }}</div>
    """, user=user)
    cache.set(cache_key, cached_content, timeout=300)

# Delete specific fragment cache
cache_key = make_template_fragment_key('sidebar_content')
cache.delete(cache_key)

# Pre-warm cache
def pre_warm_user_cache(user_id):
    cache_key = make_template_fragment_key('user_dashboard', [str(user_id)])
    if not cache.has(cache_key):
        user = User.query.get(user_id)
        content = render_template('fragments/user_dashboard.html', user=user)
        cache.set(cache_key, content, timeout=600)

Template Fragment Cache Management

Manage cached template fragments from Python code.

from flask import current_app
from flask_caching import make_template_fragment_key

def clear_user_template_cache(user_id):
    """Clear all cached template fragments for a user."""
    fragment_keys = [
        make_template_fragment_key('user_dashboard', [str(user_id)]),
        make_template_fragment_key('user_profile', [str(user_id)]),
        make_template_fragment_key('user_sidebar', [str(user_id)])
    ]
    cache.delete_many(*fragment_keys)

def invalidate_category_cache(category_id):
    """Invalidate product listing caches for a category."""
    keys_to_delete = [
        make_template_fragment_key('product_list', [str(category_id), 'regular']),
        make_template_fragment_key('product_list', [str(category_id), 'sale']),
        make_template_fragment_key('category_sidebar', [str(category_id)])
    ]
    cache.delete_many(*keys_to_delete)

def refresh_global_fragments():
    """Refresh site-wide cached fragments."""
    global_fragments = ['header_nav', 'footer_content', 'sidebar_ads']
    for fragment in global_fragments:
        cache_key = make_template_fragment_key(fragment)
        cache.delete(cache_key)

Advanced Template Caching Patterns

Complex caching scenarios and best practices.

Nested Fragment Caching:

{# Outer cache for entire section #}
{% cache 1800 "news_section" %}
<section class="news">
  <h2>Latest News</h2>
  
  {# Inner cache for expensive news list #}
  {% cache 300 "news_list" %}
  <div class="news-list">
    {% for article in get_latest_news() %}
      <article>{{ article.title }}</article>
    {% endfor %}
  </div>
  {% endcache %}
  
  {# Separate cache for sidebar #}
  {% cache 600 "news_sidebar" %}
  <aside>{{ render_news_sidebar() }}</aside>
  {% endcache %}
</section>
{% endcache %}

Conditional Caching:

{# Cache only for non-admin users #}
{% if not current_user.is_admin %}
  {% cache 300 "public_content" %}
{% endif %}

<div class="content">
  {{ expensive_content_generation() }}
</div>

{% if not current_user.is_admin %}
  {% endcache %}
{% endif %}

User-Specific Fragment Caching:

{# Cache personalized content per user #}
{% cache 600 "personalized_recommendations" current_user.id %}
<div class="recommendations">
  <h3>Recommended for {{ current_user.name }}</h3>
  {% for item in get_user_recommendations(current_user.id) %}
    <div class="recommendation">{{ item.title }}</div>
  {% endfor %}
</div>
{% endcache %}

{# Cache with user role differentiation #}
{% cache 900 "dashboard_widgets" current_user.id current_user.role %}
<div class="dashboard-widgets">
  {% if current_user.role == 'admin' %}
    {{ render_admin_widgets() }}
  {% elif current_user.role == 'manager' %}
    {{ render_manager_widgets() }}
  {% else %}
    {{ render_user_widgets() }}
  {% endif %}
</div>
{% endcache %}

Template Caching Integration

The template cache extension integrates seamlessly with Flask-Caching's main cache instance.

Cache Extension Constants:

JINJA_CACHE_ATTR_NAME = "_template_fragment_cache"
# Attribute name used to attach cache instance to Jinja2 environment

Manual Extension Usage:

from flask_caching.jinja2ext import CacheExtension, JINJA_CACHE_ATTR_NAME

# Manual registration (when with_jinja2_ext=False)
app.jinja_env.add_extension(CacheExtension)
setattr(app.jinja_env, JINJA_CACHE_ATTR_NAME, cache)

# Access cache from template context
def get_template_cache():
    return getattr(current_app.jinja_env, JINJA_CACHE_ATTR_NAME)

Performance Considerations

Cache Key Strategy:

  • Use specific, meaningful fragment names
  • Include relevant variation parameters (user_id, date, category, etc.)
  • Avoid overly long cache keys
  • Consider cache key namespace conflicts

Cache Timeout Strategy:

  • Short timeouts (1-5 minutes) for frequently changing content
  • Medium timeouts (30-60 minutes) for semi-static content
  • Long timeouts (several hours) for rarely changing content
  • Use cache deletion for immediate updates when content changes

Memory Usage:

  • Monitor cached fragment sizes
  • Implement cache eviction strategies for large fragments
  • Consider fragmenting very large template sections
  • Use appropriate cache backends for template content size

Install with Tessl CLI

npx tessl i tessl/pypi-flask-caching

docs

backends.md

core-operations.md

decorators.md

index.md

template-caching.md

tile.json